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对象是否回收的目的是:为了实现内存泄露报警. 内存泄露是指程序中对象生命周期(点击查看详情)已经进入不可见阶段,但因为编码 ...
随机推荐
- 简简单单储存过程——循环一个select结果集
原文地址:https://shitou521.iteye.com/blog/1069027 摘要:本文主要讲解了存储过程的创建.调用.以及游标的使用 ,相信掌握了游标 会对你有不错的帮助,有 ...
- 使用 LVS 实现负载均衡原理及安装配置详解(课堂随笔)
一.负载均衡LVS基本介绍 LB集群的架构和原理很简单,就是当用户的请求过来时,会直接分发到Director Server上,然后它把用户的请求根据设置好的调度算法,智能均衡地分发到后端真正服务器(r ...
- idm技术下载百度网盘
原使用教程:https://www.haorenka.org/idm.html 使用idm下载器后实际下载速度,比原网盘客户端快很多 相关软件下载 参考上面的参考教程,这里只提供对应所需要的文件,有的 ...
- 2019.10.28 IDEA入门指南(很多人问补充一篇)
Idea快速入门指南 1.安装 1.1.安装 我们使用的是最新的2017.3.4版本: 双击打开, 选择一个目录,最好不要中文和空格: 然后选择桌面快捷方式,请选择64位: 然后选择安装: 开始安装: ...
- 【转帖】【PCI-E通道是个什么东西?他是干啥的?】
[PCI-E通道是个什么东西?他是干啥的?] https://zhuanlan.zhihu.com/p/62426408 前言: 经常接触台式机的同学肯定绕不开PCI-E这个名词,因为这是台式机里最重 ...
- [转帖]CentOS 7 安装 GlusterFS
CentOS 7 安装 GlusterFS https://www.cnblogs.com/jicki/p/5801712.html 改天测试一下 我一直没有搞这一块呢. CentOS 7 Glu ...
- [.NET Core] - 使用 EF Core 的 Scaffold-DbContext 脚手架命令创建 DbContext
Scaffold-DbContext 命令 参数 Scaffold-DbContext [-Connection] <String> [-Provider] <String> ...
- python基础 — 链接 Mysql 创建 数据库和创表
重点: 1. 链接服务器的数据库 2. 创建表和格式 3. 插入多行数据 import pymysql try: host='xxx' user='xxx' passwd='xxx' db='test ...
- MGR安装记录
装好所有MySQL5.7, 打开GTID 修改my.cnf文件: ## group replication transaction_write_set_extraction = XXHASH64 ## ...
- C++ 异步编程:Boost.Asio
Boost.Asio 是一个用于网络和低级 I/O 编程的跨平台 C++ 库,它使用现代 C++ 方法为开发人员提供一致的异步模型 一个异步使用计时器的样例 #include <iostream ...