JVM内存
jvm将自己拿到的内存分成五个部分:栈,堆,程序计数器,本地方法站,方法区。
- 本地方法栈: C++的native方法运行时候的栈
- 栈: 函数运行过程中的临时变量,栈存储的对象实际是引用类型,存储的是一个地址,最终是指向堆区。
- 堆:主要存对象。
- 程序计数器:指向程序当前运行的位置
- 方法区:存取一些元数据,JDK7之前叫做永久带,JDK8之后改名为元数据空间,主要存储一些静态方法或变量(static), 类加载器(class loader)
栈+本地方法栈+程序计数器= 线程私有,每个线程会单独创建这样一份内存 。
堆和方法区是全局共享。
程序运行结束之后,会将创建的栈空间 整个删除。
堆和栈
值创建过程
如上图,首先main线程创建一个栈,保存A,之后func1函数会创建新的栈,运行结束,删除栈。
对象创建过程:
只看fun1函数,首先为变量a,b栈上申请空间,new一个对象会发生,在堆上申请一块内存,包含两个部分,一个是地址,一个是内容,默认id = 0, name = null. 堆保存一个地址指向栈中的地址。下一行id 进行赋值,下一行name 进行赋值发现String也是一个对象,在堆中 新申请一块内存,保存char数组的值内存地址,person对象中name地段保存String的地址。
运行完毕之后,栈空间删除,但是堆上的空间怎么处理呢?
GC机制,垃圾回收。
方法区
保存static 变量或者方法, 全局。
GC
如何判断对象是否需要被清楚
GCroot
-
被栈引用或者间接引用;
-
或者被本地方法栈引用或间接引用的对象;
-
或者被方法区直接或者间接引用的这些对象;
这些对象是不可以被删除。
清理堆区对象的思路
- 标记需要删除的对象—标记清理
缺点:产生内存碎片
- 标记整理 – 删除之后整理,比如删掉第一个后面的往前顶。
缺点:代价开销大
- 复制算法
将整个内存一分为二, 将对象创建在一区,然后需要删除的时候标记删除对象,之后不是直接删除,而是向二区复制不需要删除的对象。
缺点:需要两倍的内存。
实际的做法
划分堆- 年轻代(young), 老年代(0ld)
young再次划分三块:E, S, S (为表区分,S0, S1)
new对象出生在E区,E区快满之后,触发GC,也叫作young GC, 使用复制算法,复制到S0区。
对象朝生夕死,产生的比较大,但是幸存下来比较小,所以E区较大,S区较小。
为什么需要两个S区,
这两个S区交替工作,比如E幸存到S0区,删除E区和S1区,下一次E区快慢之后,标记S0和E区,将所有的幸存者保存到S1区,清空另外两个区。如此反复。
OLD区
: 每一次youngGC,年龄就会加一,如果每一次Young GC都活下来了,如果满6岁,不在向S中复制,直接放在OLD区中维护,省的每次都在young区复制。
OLD保存六岁以上的对象还有一些大对象
大对象的消耗比较大,比如一个100000000大小的int数组。
OLD的内存快满也会触发GC, 每次OLD GC一般也会引起young GC,这也叫full GC, 引起Stop the world, java程序直接暂停,全力进行垃圾回收, 主要使用 标记清理或者标记整理算法。
垃圾收集器:ParNew, CMS, G1,其中G1有全新的理念。
指针压缩
对象的组成:对象的头和body
头也分成三个部分:
-
mark world(8B) ,记录对象信息,是否锁住,GC年龄等
-
Klass world(4B), 指向C++中对象的地址,Klass指针指向metaspace区的对象, Klass对象记录对象的元数据信息。
-
Array length(4B),对象不是数组类型不存在这个字段
栈中保存值类型,也保存对象引用,如果指针压缩就是4字节,没有压缩就是8字节.
为什么对象的指针可以是4字节
因为java对象是8字节对齐,每个地址住8个字节而不是1个字节,所以4字节,可以表示2^32 * 8 Byte= 32GB的内存地址。
堆内存在32G以内都是默认开启指针压缩,每个对象的地址用4字节宝石,但是堆超过32G无法压缩每个对象地址必须要用8字节。
可能33G, 34G堆大小中申请的对象的个数反而没有32位中申请的多。
地址变大了,变成8个字节了。
普通对象指针压缩技术
: 四字节地址可以对32G内存寻址。
klass C++对象并不是普通对象,为什么也可以压缩实现呢?
在元空间中,开启压缩后,KLASS部分位于压缩累空间上,包括ITABLE, VTABLE,压缩类空间是连续的4GB的空间,这里的32bit确实是表示4GB的空间。
避免创建巨大的动态代理链,会占用metaspace,撑爆压缩累空间,程序报错。
metaSpace开启指针压缩之后,分成两个部分:
-
压缩类空间:一些KLASS, itable等较小的数据
-
non-Class: 除上面之间的元数据信息;