Java对象内存分配原理与布局
当一个对象被创建了,那在JVM中是如何的从一个对象不存在到存到,然后将对象存放在什么地方呢?这次主要来探讨一下Java对象创建的过程。
new关键字创建对象的3个步骤:
1、在堆内存中创建出对象的实例。
当我们用new关键字来创建对象的实例时,JVM首先会检查new这个指令的参数是不是能造常量池中定位成一个类的符号引用,然后再检查该符号引用所对应的类是不是被正常的加载、连接、初始了,如果木有则必须要完成类的加载过程,当事先的准备阶段都结束之后,接着JVM则为该对象分配内存,当对像加载完之后该对象要分配多少内存其实是已经确定的一件事情了。而在Java堆中内存整体来说是分成2部分的,第一部分内存是已经被使用或者说已经被占用的,而第二部分内存则是空闲的可以被使用的,而已经被占用的空间和未被使用的空间又分为两种情况:
第一种情况:在堆内存中已经截然有序的将已使用和未使用的内存空间给分离开了,比如说左侧是已经占用的空间,而右侧是未被占用的空间。中间可以通过一个指针来指向,这种情况下如果新创建的对象则会存在于未被占用的空间中,然后指针发生了一个移动指向了下一个可以被使用的内存空间,对于这种case我们可以称之为指针碰撞(前提是堆中的空间通过一个指针进行分割,一侧是已经被占用的空间,另一侧是未被占用的空间)。
第二种情况:这种Java堆内存并未像第一种情况说得这么理想,而是不归整交织在一起了,这种情况下肯定不能去移动指针这么简单来进行指向了,这时需要记录一个列表用来标识哪些地方是内存已经被使用了的,哪些是未被使用了的,并且还要记录未被使用的大小是多少,这种情况下当要给对象分配内存时,则需要从列表中选出来可以容纳新创建对象大小的空间,然后把新的对象放置在可以容纳的内存当中,并且要修改列表的记录,这种做法则称之为空闲列表(前提是堆内存空间中已被使用与未被使用的空间是交织在一起的,这时,虚拟机就需要通过一个列表来记录哪些空间是可以使用的,哪些空间是已被使用的,接下来找出可以容纳下新创建对象的且未被使用的空间,在此空间存放该对象,同时还要修改列表上的记录)。
FAQ:为啥会有这两种情况呢?其实是跟垃圾收集【未来会专门学到它】器息息相关的,有一些垃圾收集器是带压缩过程,所谓压缩过程是指垃圾收集器在执行一次垃圾回收的时候,除了把真正垃圾的对象给清除掉之外,此时已使用和未使用的内存一定是不连续的,那么它们在做完清除工作之后还要做一次对象的移动操作,也就是将已被使用的和未被使用的分文别类的给排开,此时就可以用指针碰撞的方式来解决对象存放的问题;而有些垃圾收集器在垃圾回收之后就立马结束了,不会对对象进行一个移动操作,从而导致已使用和未被使用的内存交织在一起的,此时就只能用空闲列表的方式来解决对象存放的问题啦。
2、为对象的实例成员变量【而非静态成员变量】赋初值。
这个不多解释了,在之前的类加载中详细说过。
3、将对象的引用返回。
对象在内存中的布局【了解既可】:
对象的内存布局其实就是指一个对象它存放的信息有啥, 总共分为三部分:
1、对象头。
它会存放对象自身的一些运行时的数据信息,比如说一个对象有一个hash码、还有分代的一个信息等,把这些信息都放置在对象头里面。
2、实例数据 (既我们在一个类中所声明的各项信息)。如成员变量。
3、对齐填充(可选),其实就是起到一些点位符的作用,比如说要求8的倍数,如果不够8的话被0等。
引用访问对象的方式:
这个在之前【https://www.cnblogs.com/webor2006/p/9876493.html】已经详细学习过了,其实就是两种形态,回顾一下:
1、使用句柄的方式。

2、使用直接指针的方式。

这两种有啥区别,这里也再贴出来回顾一下,纯之前学的东东:




好,接下来回到咱们熟悉的代码上来,上面一大堆的理论还得由实践将其进行验证,这里编写一个可以在堆空间出现内存溢出异常的代码,具体做法如下:

也就是写一个死循环,不断的往堆中新建MyTest1对象,最终肯定会撑爆JVM的堆空间从而来模拟出堆内存溢出,我们知道JVM是可以有参数来调整截内存空间的,为了让这个程序更快的出现,我们可以手动来修改JVM的参数,如下:


其中还设置了一个当发生内存溢出时来将内存的信息给dump出来,其实就类似于Android中来分析内存也是需要dump内存信息一样,如下:

下面来运行一下,看是不是很快就报内存溢出异常了:

立竿见影嘛,其中内存异常的原因也可以清楚的看到是由于java的堆空间:

其中可以看到dump文件已经创建了:

那咱们在工程中刷新一下,发现貌似木有看到dump文件呀,其实在IntelliJ IDEA中是没有将其显示出来而已,咱们得在目录文件中来查看,瞅下:

那dump文件生成了怎么查看呢,莫要急,下次再继续学~~
Java对象内存分配原理与布局的更多相关文章
- Java 对象内存分配与回收
JVM内存区域模型: * 程序计数器,内存区域极小,是当前线程的字节码执行行号指示器: * 虚拟机栈.本地方法栈,即平时所说的“栈”,是虚拟机用来执行方法(包括Java.非Java方法)时,使用的临时 ...
- Java对象内存布局
本文转载自Java对象内存布局 导语 首先直接抛出问题 Unsafe.getInt(obj, fieldOffset)中的fieldOffset是什么, 类似还有compareAndSwapX(obj ...
- 深入Java核心 Java内存分配原理精讲
深入Java核心 Java内存分配原理精讲 栈.堆.常量池虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同.本文将深入Java核心,详细讲解Java内存分配方面的知识. Java内存分 ...
- java内存分配原理
一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 ◆堆:存放用new产生的数据 ◆静态域:存放在 ...
- [Java]Java类和对象内存分配详解
描述 代码说明: 一.当Person p1 = new Person();第一次被调用时需要做两件事: 1.先判断类加载器是否加载过Person类,如果没有则加载到Person类型到方法区 2.在堆中 ...
- java中内存分配策略及堆和栈的比较
Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...
- JAVA虚拟机内存分配与回收机制
Java虚拟机(Java Virtual Machine) 简称JVM Java虚拟机是一个想象中的机器,在实际的计算机上通过软件模拟来实现.Java虚拟机有自己想象中的硬件,如处理器.堆栈.寄存器等 ...
- JVM内存分配原理
堆栈常量池等内存分配原理详解 存储的方式: 寄存器 栈(stack) 堆(heap) 静态域 常量池 非RAM存储 JAVA寄存器 最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. ...
- [Java] 监控java对象回收的原理与实现
监控Java对象回收的原理与实现 一.监控Java对象回收的目的 监控Java对象是否回收的目的是:为了实现内存泄露报警. 内存泄露是指程序中对象生命周期(点击查看详情)已经进入不可见阶段,但因为编码 ...
随机推荐
- Django:ORM中ForeignKey外键关系分析
假设有两张表,Role和User,因为多个用户会对应一个角色,属于多对一关系,所以User中的rolename字段使用ForeignKey,第一个参数为要关联的表Role,第二个参数related_n ...
- 安装 KVM
安装 KVM 需要的包 sudo apt-get install -y qemu-kvm qemu-system libvirt-bin virt-manager bridge-utils vlan ...
- Winsock.简单UDP
PS:vs2017 编译C++代码 支持 XP:项目属性-->链接器-->系统-->需要的最小版本--> 输入 "5.1" 1.ZC:测试:c向s 发送长度 ...
- [概率DP][消元法][CF24D]损坏的机器人
Description 有一只坏了的机器人站在一个\(n\times m\)的网格里,初始位置在\((x,y)\).现在每个单位时间内它会随机选左右下三个方向走,如果它随机的方向会走出网格就不会往这个 ...
- 深入css过渡transition
通过过渡transition,可以让web前端开发人员不需要javascript就可以实现简单的动画交互效果.过渡属性看似简单,但实际上它有很多需要注意的细节和容易混淆的地方. 过渡transitio ...
- 十分钟教会你使用安卓热修复框架AndFix
腾讯最近开发出一个Tinker,阿里也有一个Dexposed框架,当然还有一个就是今天的主角热修复框架AndFix.接下来,我会从它的概念.原理.使用方法等为你详细介绍. 1.什么是AndFix? A ...
- JVM(三) 对象的创建过程
1.对象的创建过程 1.1 . 给对象分配内存 对象的内存分配有两种方式,一种是指针碰撞另外一种是空闲列表的方式,堆是否规整由我们垃圾回收器来决定的 ,如果垃圾回收带有我们的压缩算法,那么他会规整的分 ...
- Django源码分析之启动wsgi发生的事
前言 好多人对技术的理解都停留在懂得使用即可,因而只会用而不会灵活用,俗话说好奇害死猫,不然我也不会在凌晨1.48的时候决定写这篇博客,好吧不啰嗦了 继续上一篇文章,后我有个问题(上文:&qu ...
- 039 Android SQLite数据库(了解)
1.介绍 注意:当有大量相似结构的数据需要存储的时候,需要使用数据库. 2.SQLiteOpenHelper简介 注意:数据库的创建方法总结: (1)定义一个类继承SQLiteOpenHelper o ...
- 修改Linux服务器中的MySql密码
1.可以直接在数据库中修改,因为知道root密码,所以直接登录 mysql -uroot -p 2.查看一下数据库,修改root密码需要使用如下图所示的mysql数据库 3.通过use mysql指明 ...