概述
写作背景
我的Java学习实现从C的学习开始的,对于C语言的内存分布有了了解后,在对比了的内存分布后发现略有出入:其归根结底是真实计算机和JVM虚拟计算机的区别;
C语言中内存分布及程序运行中(BSS段,数据段,代码段,堆段)
BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。
数据段 :数据段(data segment)通常是指用来存放程序中 已初始化 的 全局变量 的一块内存区域。数据段属于静态内存分配。
代码段: 代码段(code segment/text segment)通常是指用来存放 (函数体,类成员函数,全局变量)程序执行代码 的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于 只读 , 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些 只读的变量 ,例如字符串常量等。程序段为程序代码在内存中的映射.一个程序可以在内存中多有个副本.
堆(heap) :堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc/free等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张)/释放的内存从堆中被剔除(堆被缩减)
栈(stack) :栈又称堆栈, 存放程序的 局部变量 (但不包括static声明的变量, static 意味着 在数据段中 存放变量)。除此以外,在函数被调用时,栈用来传递参数和返回值。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。
向下增长即地址由高到低;
-
java内存结构(jvm)
1. Heap(堆):
- 堆得内存由-Xms指定,默认是物理内存的1/64;最大的内存由-Xmx指定,默认是物理内存的1/4。
- 默认空余的堆内存小于40%时,就会增大,直到-Xmx设置的内存。具体的比例可以由-XX:MinHeapFreeRatio指定
- 空余的内存大于70%时,就会减少内存,直到-Xms设置的大小。具体由-XX:MaxHeapFreeRatio指定。
2. MethodArea(方法区域):
1)有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生GC,在这里进行的GC主要是对方法区里的常量池和对类型的卸载
2)方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
该区域是被线程共享的。
3)方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。 对应是Permanet Generation, 通过-XX:PermSize来设置
为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢?
整个永久代有一个 JVM 本身设置固定大小上限,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,并且永远不会得到 java.lang.OutOfMemoryError。你可以使用 -XX:MaxMetaspaceSize
标志设置最大元空间大小,默认值为 unlimited,这意味着它只受系统内存的限制。-XX:MetaspaceSize
调整标志定义元空间的初始大小如果未指定此标志,则 Metaspace 将根据运行时的应用程序需求动态地重新调整大小。
当然这只是其中一个原因,还有很多底层的原因,这里就不提了。
3. JavaStack(java的栈):虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息本地方法栈:本地方法栈则是为虚拟机使用到的Native方法服务。虚拟机只会直接对Javastack执行两种操作:以帧为单位的压栈或出栈。通过-Xss来设置, 若不够会抛出StackOverflowError
4. ProgramCounter(程序计数器):每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的饿地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。
- 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
- 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。
5. Nativemethodstack(本地方法栈):保存native方法进入区域的地址
为什么Java可以先试用函数,后定义?
归根结底是因为java是面向对象语言,写代码就是抽象类的过程;所有的方法,字段都在类里,运行时将整个类放在方法区(数据共享区)充当的只是模板的作用,所以方法定义先后就不要紧了,当具体到某一个实例对象时它实例化了类的所有方法,当他调用一个需要用到在类后面才定义的方法时;而自己已经有所有方法的实例所以就不会报错,去静态方法区查找相应的方法模板传参实例化就行了;
而C++不能算面向对象程序设计语言;他的类只能算结构体的扩展吧;
最后
以上就是痴情荔枝为你收集整理的C语言内存分布和Java内存分布的全部内容,希望文章能够帮你解决C语言内存分布和Java内存分布所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复