指针碰撞和空闲列表

本文围绕Java开发展开,介绍了Java在虚拟机内存管理下,内存泄露和溢出问题排查困难。阐述了Java堆中对象内存分配的指针碰撞法和空闲列表法,以及解决内存分配并发问题的CAS和TLAB方式。还说明了创建对象的几个要点,如类加载检查、分配内存等。

对于Java开发来说,在虚拟机内存管理的帮助下,不需要为每个新的对象在代码层面分配内存,回收内存,比如像C语言那样操作。所以在正常情况下,内存泄露和内存溢出等问题也不太容易出现。所以要是运行中的程序出现了内存泄露问题,排查还是有一定困难。

Java堆是被所有线程共享的一块内存区域,主要用于存放对象实例,为对象分配内存就是把一块大小确定的内存从堆内存中划分出来,通常有指针碰撞和空闲列表两种实现方式。

1.指针碰撞法
假设Java堆中内存时完整的,已分配的内存和空闲内存分别在不同的一侧,通过一个指针作为分界点,需要分配内存时,仅仅需要把指针往空闲的一端移动与对象大小相等的距离。使用的GC收集器:Serial、ParNew,适用堆内存规整(即没有内存碎片)的情况下。

2.空闲列表法
事实上,Java堆的内存并不是完整的,已分配的内存和空闲内存相互交错,JVM通过维护一个列表,记录可用的内存块信息,当分配操作发生时,从列表中找到一个足够大的内存块分配给对象实例,并更新列表上的记录。使用的GC收集器:CMS,适用堆内存不规整的情况下。

内存分配并发问题

在创建对象的时候有一个很重要的问题,就是线程安全,因为在实际开发过程中,创建对象是很频繁的事情,作为虚拟机来说,必须要保证线程是安全的,通常来讲,虚拟机采用两种方式来保证线程安全:

  • CAS: CAS 是乐观锁的一种实现方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。虚拟机采用 CAS 配上失败重试的方式保证更新操作的原子性。
  • TLAB: 为每一个线程预先分配一块内存,JVM在给线程中的对象分配内存时,首先在TLAB分配,当对象大于TLAB中的剩余内存或TLAB的内存已用尽时,再采用上述的CAS进行内存分配。

如果想多了,创建一个对象还是挺麻烦的,需要这么多步骤,那么我们在开发过程中尽量非必须的对象创建呢?

创建对象有以下几个要点

  1. 类加载机制检查:JVM首先检查一个new指令的参数是否能在常量池中定位到一个符号引用,并且检查该符号引用代表的类是否已被加载、解析和初始化过
  2. 分配内存:把一块儿确定大小的内存从Java堆中划分出来
  3. 初始化零值:对象的实例字段不需要赋初始值也可以直接使用其默认零值,就是这里起得作用
  4. 设置对象头:存储对象自身的运行时数据,类型指针
  5. 执行<init>:为对象的字段赋值

学习前人笔记,记录一下!

参考:

https://www.jianshu.com/p/eaef248b5a2c

https://juejin.im/post/5b7d69e4e51d4538ca5730cb

转载于:https://my.oschina.net/u/2277632/blog/3045363

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值