深入理解JVM_内存管理对象访问与大小02

1、对象访问:

在java语言中,对象访问如何进行的?

(1)最简单的访问,也会涉及java栈、java堆和方法区这三个最重要的内存区域之间的关联关系。

Object obj = new Object();

<1> “Object obj”:反应到java栈的本地变量表中,作为一个reference类型数据出现。

<2> “new Object()”:反应到java堆中,形成一块存储了Object类型所有实例数据值的结构化内存。这块内存的长度不是固定的。

<3> java堆中还必须包含能查找到此对象类型数据(如对象类型、父类、实现的接口、方法等)的地址信息,这些类型数据则存储在方法区中。

(2)由于reference类型在java虚拟机规范里只规定了一个指向对象的引用,并没有定义这个引用应该通过哪种方式去定位,以及访问到java堆中的对象的具体位置。主流的访问方式有两种:

<1> 使用句柄;

Java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,此句柄中包含了:“对象实例数据”和“类型数据”各自具体的地址信息。具体如下图:

<2> 直接指针。

Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,reference中直接存储的就是对象地址。如下图:

<3> 两种方式的优缺点:

(1) 句柄优点:reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要被改变。

(2) 直接指针优点:速度很快,它节省一次指针定位的时间开销。Sun HotSpot而言,就是使用此种方式。

2、Java对象的大小:

基本数据的类型的大小是固定的。非基本类型的java对象,其大小就值得商榷了。

在java中,一个空object对象的大小是8byte。这个大小只是保存堆中一个没有任何属性的对象的大小。如下语句:

Object obj = new Object();

这样在程序中完成了一个java对象的生命,但是它所占的空间为:4byte+8byte。期中4byte就是上面所说的java栈中保存引用的所需要的空间,而8byte则是java堆中对象的信息。因为java中非基本类型的对象都需要继承Object对象,所有不论什么样的java对象,其大小都必须大于8byte。

有了Object对象的大小,我们就可以计算其他对象的大小了。

Class NewObject {

int count;

boolean flag;

Object ob;

}

其大小为:空对象大小(8byte)+int大小(4byte)+Boolean大小(1byte)+空Object引用的大小

(4byte)=17byte。但是因为Java在对对象内存分配时都是以8的整数倍来分,因此大于17byte的最接

近8的整数倍的是24,因此此对象的大小为24byte。

程序计数器、虚拟机栈、本地方栈3个区域随线程而生,随线程而灭,栈中的栈帧随着方法的进入和退出而执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的。

以下内容待定:

2、内存分配

java对象所占用的内存主要从堆上进行分配,堆是所有线程共享的,因此堆上分配内存时需要进行加锁,导致了创建对象开销比较大。当堆上空间不足时,会触发GC,如果GC后空间仍然不足,则出OutOfMemory错误信息。

JDK提升内存分配的效率,会为每个新创建的线程在新生代的Eden Space上分配一块独立的空间。这个空间称为TLAB(Thread Local Allocation Buffer),其大小有JVM根据运行情况计算而得。

可通过:-XX:TLABwasteTargetPercent来设置TLAB可占用的Eden Space的百分比,默认值为1%。

JVM将根据这个比率,线程数量及线程是否频繁分配对象来给每个线程分配合适大小的TLAB空间。在TLAB上分配内存时不需要加锁,因此JVM在给线程中的对象分配内存时会尽量在TLAB上分配,如果对象过大或TLAB空间已用完,则仍然在堆上进行分配。

因此在编写java程序时,通常多个小的对象比大的对象分配起来更加高效。可通过在启动参数上增加-XX:+PrintTLAB来查看TLAB空间的使用情况。

除了从堆上分配及从TLAB上分配外,还有一种基于逃逸分析直接在栈上进行分配的方式。

时间: 2024-11-08 19:13:32

深入理解JVM_内存管理对象访问与大小02的相关文章

【转】理解JVM内存区域

引言 对于C++程序员,内存分配与回收的处理一直是令人头疼的问题.Java由于自身的自动内存管理机制,使得管理内存变得非常轻松,不容易出现内存泄漏,溢出的问题. 不容易不代表不会出现问题,一旦内存泄漏或溢出的情况发生,调试起来会变得非常困难.这就要求我们对虚拟机的内存区域有深入的理解.最终能够判断内存方面的异常发生时,具体在JVM中的位置. 内存区域 JVM运行时,首先需要类加载器(ClassLoader) 加载所需类的字节码,加载完毕交由执行引擎执行,执行过程中需要一段空间来存储数据(类比CP

如何优化cocos2d程序的内存使用和程序大小

在我完成第一个游戏项目的时候,我深切地意识到"使用cocos2d来制作游戏的开发者们,他们大多会被cocos2d的内存问题所困扰".而我刚开始接触cocos2d的时候,社区里面的人们讨论了一个非常有意义的话题:"请简单地讲述你认为新手cocos2d程序员在他开始编码之前,最应该先知道,或者应该关注和注意的事项."这个问题的答案很多,有人讲是"如何加载和保存游戏数据",有人讲的是"如何实现有限状态机"等等.而最吸引我的则是,有一

[转载]windows任务管理器中的工作设置内存,内存专用工作集,提交大小详解

windows任务管理器中的工作设置内存,内存专用工作集,提交大小详解 http://shashanzhao.com/archives/832.html 虽然是中文字,但是理解起来还是很困难,什么叫工作设置内存,什么叫内存专用工作集,什么叫提交大小,区别是什么,让人看了一头雾水. 通俗的讲工作设置内存是程序占用的物理内存(包含与其他程序共享的一部分), 内存专用工作集是程序独占的物理内存, 提交大小是程序独占的内存(包含物理内存和在页面文件中的内存). 注:页面文件就是存放不在物理内存中的内存,

深入理解Java内存模型之系列篇[转]

原文链接:http://blog.csdn.net/ccit0519/article/details/11241403 深入理解Java内存模型(一)——基础 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递. see:命令式编程.函数式编程 在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存

深入理解Java内存模型(三)——顺序一致性

本文属于作者原创,原文发表于InfoQ:http://www.infoq.com/cn/articles/java-memory-model-3 数据竞争与顺序一致性保证 当程序未正确同步时,就会存在数据竞争.java内存模型规范对数据竞争的定义如下: 在一个线程中写一个变量, 在另一个线程读同一个变量, 而且写和读没有通过同步来排序. 当代码中包含数据竞争时,程序的执行往往产生违反直觉的结果(前一章的示例正是如此).如果一个多线程程序能正确同步,这个程序将是一个没有数据竞争的程序. JMM对正

深入理解Linux内存管理

引用:Live and Learn 1. 内存地址 以Intel的中央处理器为例,Linux 32位的系统中,物理内存的基本单位是字节(Byte),1个字节有8个二进制位.每个内存地址指向一个字节,内存地址加1后得到下一个字节的地址.这里用以表示物理内存实际位置的地址,就是通常所说的物理地址(Physical Address).CPU正在执行的进程代码.进程数据和栈区数据等,都临时保存在物理内存中. 线性地址(Linear Address,亦即虚拟地址 Virtual Address)是出于以下

深入理解java内存模型

深入理解Java内存模型(一)——基础 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递. 在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信.在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信. 同步是指程序用于控制不同线程之

【转】深入理解Java内存模型(三)——顺序一致性

数据竞争与顺序一致性保证 当程序未正确同步时,就会存在数据竞争.java内存模型规范对数据竞争的定义如下: 在一个线程中写一个变量, 在另一个线程读同一个变量, 而且写和读没有通过同步来排序. 当代码中包含数据竞争时,程序的执行往往产生违反直觉的结果(前一章的示例正是如此).如果一个多线程程序能正确同步,这个程序将是一个没有数据竞争的程序. JMM对正确同步的多线程程序的内存一致性做了如下保证: 如果程序是正确同步的,程序的执行将具有顺序一致性(sequentially consistent)-

( 转)深入理解java内存模型系列

深入理解Java内存模型(一)——基础 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来交换信息.在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递. 在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信.在消息传递的并发模型里,线程之间没有公共状态,线程之间必须通过明确的发送消息来显式进行通信. 同步是指程序用于控制不同线程之