网站开发调用别人网站的组件,做网站需要懂哪些语言,seo关键词使用,中国icp备案网站jvm如何进行内存分配 内存分配方式内存分配方式的选择并发场景下的内存分配内存空间的初始化构造函数 内存分配方式
指针碰撞空闲列表
指针碰撞法#xff1a; 假设Java堆中内存是绝对规整的#xff0c;所有被使用过的内存都被放在一边#xff0c;空闲的内存被放在另一边 假设Java堆中内存是绝对规整的所有被使用过的内存都被放在一边空闲的内存被放在另一边中间放着一个指针作为分界点的指示器那所分配内存就仅仅是把那个指针向空闲空间方向挪动一段与对象大小相等的距离这种分配方式称为“指针碰撞” 空闲列表法 但如果Java堆中的内存并不是规整的已被使用的内存和空闲的内存相互交错在一起那就没有办法简单地进行指针碰撞了虚拟机就必须维护一个列表记录上哪些内存块是可用的在分配的时候从列表中找到一块足够大的空间划分给对象实例并更新列表上的记录这种分配方式称为“空闲列表” 内存分配方式的选择
Java堆是否规整又由所采用的垃圾收集器是否带有空间压缩整理Compact的能力决定。因此当使用Serial、ParNew等带压缩整理过程的收集器时系统采用的分配算法是指针碰撞既简单又高效而当使用CMS这种基于清除Sweep算法的收集器时理论上就只能采用较为复杂的空闲列表来分配内存。
并发场景下的内存分配
并发场景下可能出现多个线程同时创建对象的情况这种时刻的内存分配是明显存在问题的如果在给A对象分配好内存了但是指针还没来得及修改此时B对象刚获取指针的位置并且分配内存那么就会造成内存区域重叠这种情况的处理方案有两种。 一种是对分配内存空间的动作进行同步处理——实际上虚拟机是采用CAS配上失败重试的方式保证更新操作的原子性 另外一种是把内存分配的动作按照线程划分在不同的空间之中进行即每个线程在Java堆中预先分配一小块内存称为本地线程分配缓冲Thread Local AllocationBufferTLAB哪个线程要分配内存就在哪个线程的本地缓冲区中分配只有本地缓冲区用完了分配新的缓存区时才需要同步锁定。
其实第一种方案就是给分配内存的操作加锁指针碰撞的时候每个线程都不断尝试获取锁而拿到锁的线程只有分配完对象内存空间并且修改指针后才释放锁并通知其他线程保证原子性。而加锁必然会造成性能上的开销但是如果使用第二种方式即使用缓冲区也就是经典的以空间换时间思想来减少加锁操作保证运行的效率。
内存空间的初始化
内存分配完成之后虚拟机必须将分配到的内存空间但不包括对象头都初始化为零值如果使用了TLAB的话这一项工作也可以提前至TLAB分配时顺便进行。这步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用使程序能访问到这些字段的数据类型所对应的零值。
构造函数
在上面工作都完成之后从虚拟机的视角来看一个新的对象已经产生了。但是从Java程序的视角看来对象创建才刚刚开始——构造函数即Class文件中的()方法还没有执行所有的字段都为默认的零值对象需要的其他资源和状态信息也还没有按照预定的意图构造好。
一般来说由字节码流中new指令后面是否跟随invokespecial指令所决定Java编译器会在遇到new关键字的地方同时生成这两条字节码指令但如果直接通过其他方式产生的则不一定如此new指令之后会接着执行init()方法按照程序员的意愿对对象进行初始化这样一个真正可用的对象才算完全被构造出来。