Java内存分配

内存分配

这里写图片描述
1. 程序计数器(线程私有,当前线程执行字节码的行号指示器,Native方法为空Undefined)
2. 虚拟机栈(线程私有,Java方法,每个方法在执行的时候都会创建栈帧,用于储存局部变量表【对象引用+基本数据类型】,操作数栈,动态链接,方法出口等,每个方法的执行和完成,对应着栈帧在虚拟机栈的入栈和出栈)
3. 本地方法栈(线程私有,Native方法)
4. (线程共享,几乎所有对象都在堆分配内存:1.新生代:Eden空间,FromSurvivor空间,ToSurvivor空间 2.老年代 3.线程共享的堆内存还可能会划分出多个线程私有的分配缓冲区TLAB(ThreadLocalAllocationBuffer))
5. 方法区(线程共享,用于储存虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码:class文件保存的信息:类的版本、字段、方法、接口和class的常量池(用于存放编译器生成的各种字面量和符号引用)等,运行时常量池:对于class文件的常量内容,在类被加载时进入方法区的运行时常量池)
6. 直接内存(JDK的NIO的操作,引入了基于通道与缓冲区的IO防辐射,可以使用Native函数库直接分配堆外内存,通过DriectByteBuffer对象作为制片内存的引用进行操作,避免Java堆和Native堆的数据来回拷贝)

对象的创建

  1. 对类的初始化和加载
  2. 创建对象方式:内存绝对规整->指针碰撞(Compact回收算法的分配方式),内存不规整->空闲列表(CMS的Mark-Sweep回收算法的分配方式)
  3. 分配对象的时候保证同步:1. CAS+失败重试 2.TLAB(ThreadLocalAllocationBuffer):本地线程缓存
  4. 对象内存布局:头信息(header),实例数据,填充对齐

对象的访问定位:

  1. 使用句柄:本地变量表->句柄池(堆,到对象实例的指针+到对象类型的指针)->对象实例数据(堆)+对象类型数据(方法区)
  2. 使用直接指针:本地变量表->对象实例数据(包含对象类型的指针)->对象类型数据(方法区)
    区别:
    句柄稳定,只需修改句柄指针而不用修改实例数据
    直接访问速度快,只需一次访问内存

垃圾回收

垃圾回收动作何时执行?
当年轻代内存满时,会引发一次普通GC,该GC仅回收年轻代。需要强调的是,年轻代满是指Eden代满,Survivor满不会引发GC
当年老代满时会引发Full GC,Full GC将会同时回收年轻代、年老代
当永久代满时也会引发Full GC,会导致Class、Method元信息的卸载

何时会抛出OutOfMemoryException
并不是内存被耗空的时候才抛出,JVM98%的时间都花费在内存回收,每次回收的内存小于2%

更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC
更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率

JDK8元空间

Java8中去掉了虚拟机中的永久代,而是替换成本机内存的元空间,两者存储信息相同,但是元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存,不会产生虚拟机的内存溢出,但是还是受限于本机内存的大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值