[JVM]JVM内存基础

JVM内存分区:

线程私有:虚拟机栈/本地方法栈/程序计数器(当前线程执行的字节码计数器,改变计数器的值可以进行程序的跳转,循环,异常处理等操作)
公有:方法区(包括常量池(用于存放字段值和符号引用)等,程序加载时将编译后的class文件字节码加载到此区域)/堆

堆的分区:
新生代:eden区,survivor0, survivor1,
老年代

1.Eden区

    Eden区位于Java堆的年轻代,是新对象分配内存的地方,由于堆是所有线程共享的,因此在堆上分配内存需要加锁。而Sun JDK为提升效率,会为每个新建的线程在Eden上分配一块独立的空间由该线程独享,这块空间称为TLAB。在TLAB上分配内存不需要加锁,因此JVM在给线程中的对象分配内存时会尽量在TLAB上分配。如果对象过大或TLAB用完,则仍然在堆上进行分配。如果Eden区内存也用完了,则会进行一次Minor GC(young GC)

2.Survival from to

    Survival区与Eden区相同都在Java堆的年轻代。Survival区有两块,一块称为from区,另一块为to区,这两个区是相对的,在发生一次Minor GC后,from区就会和to区互换。在发生Minor GC时,Eden区和Survivalfrom区会把一些仍然存活的对象复制进Survival to区,并清除内存。Survival to区会把一些存活得足够旧的对象移至年老代。

3.年老代

    年老代里存放的都是存活时间较久的,大小较大的对象,因此年老代使用标记整理算法。当年老代容量满的时候,会触发一次Major GC(full GC),回收年老代和年轻代中不再被使用的对象资源

对象的创建:

new ClassName()
1.new关键字在堆中分配该对象大小的内存
2.编译器自动生成的<init>函数对该内存进行初始化
分配内存的过程按照虚拟机内存管理的方式不同(可用内存是否连续)分为:
1.Bump the pointer(指针碰撞)
2.Free List(空闲列表)
这种分配内存的方式易产生同步问题,可以通过CAS失败重试或用本地内存缓冲TLAB(thread local allocation buffer)

对象在堆中的存储分为三部分:对象头(对象的hashcode,类信息,GC的分代年龄)+实例数据 + padding
在对象创建后将首地址赋值给该线程栈上新入栈的引用类型(不使用句柄池)
将句柄池中的指针赋值给新入栈的引用,该方式可以保证GC进行过程中移动对象的位置后,ref指向的地址不改变,只改变句柄池中的地址即可
如P49图示

猜你喜欢

转载自blog.csdn.net/weixin_41985660/article/details/82939620