文档章节

java虚拟机内存 对象创建引用 概述

_无问西东
 _无问西东
发布于 08/20 23:22
字数 1718
阅读 6
收藏 0

1、Java虚拟机运行时数据分区图

程序计数器:线程私有,是一块较小的内存空间,它是当前线程所执行的字节码文件的行号指示器

java虚拟机栈:线程私有,其生命周期与线程相同,这也就是我们平时所粗略分的堆/栈中的栈。虚拟机栈描述的是java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接方法出口等信息。每个方法从调用直至执行完成的过程,就对应着一个栈桢在虚拟机栈中入栈到出栈的过程。局部变量表所需要的内存空间在编译期间便完成了分配,当进入一个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

本地方法栈:与虚拟机栈作用相似,他们的区别是虚拟机栈是为虚拟机执行java方法(字节码)服务,本地方法栈则是为虚拟机使用native方法服务。虚拟机规范中对本地方法栈中方法使用的语言、方式和数据结构没有限制,因此不同的虚拟机可以自由的实现。而且有的虚拟机会直接把本地方法栈和虚拟机栈合二为一(如Sun HotSpot)

Java堆(Java Heap):堆是java虚拟机所管理的内存中最大的一部分,java堆是被所有线程共享的一块内存区域,在虚拟机启动的时候创建,其存在的目的就是存放对象实例,几乎所有的对象实例和数组都会在堆上分配内存。但是随着JIT编译器与逃逸分析技术的逐渐成熟,栈上分配,标量替换优化技术将会导致一些变化,所有对象都在堆上分配也不再那么“绝对”

方法区:所有线程共享,用于存储已经被虚拟机加载的类信息,常量,静态变量,即使编译器编译后的代码等数据,虽然java虚拟机把它描述为堆的一个逻辑部分,但是其有个别名就做非堆(Non-Heap)。

运行时常量池:是方法区的一部分,Class文件除了有类的版本、字段、方法等描述信息以外,还有一项信息是常量池(Constant pool table)用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

直接内存:直接内存并不是Java虚拟机运行时数据区域的一部分,也不是java虚拟机规范中定义的内存区域。但是这部分内存也会被平凡的使用,而且一样会发生OOM。JDK1.4中加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的IO方式,可以直接使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer的对象作为这块内存的引用进行操作,这样能在一些场景中显著提高性能,因为避免了从java堆和Native堆中复制数据。直接内存的分配不受java堆大小限制,但是肯定会受到机器总内存(RAM,SWAP,或者分页文件)和处理器寻址空间的限制,毕竟它也是内存。

2、对象的创建

在java语言中创建对象是通过new关键字来进行的,这里所说的是当虚拟机遇到new指令后是怎么样来创建一个对象的。这里仅仅讨论一般对象的创建(不包括数组和Class对象)

当虚拟机遇到new指令后,首先回去检查这个指令的参数是否能够在常量池中定位到一个类的符号引用,并去检查这个符号引用代表的类是否已经被加载、解析和初始化过,如果没有就必须先执行相应的类加载。

类加载检查通过,虚拟机会为新的对象分配内存,因此对象所需内存的大小将会在类加载完毕后被完全确定,为对象分配空间的过程就是将一块大小确定的内存从java堆中划分出来。

3、对象的定位

那么对于创建的对象虚拟机是怎么在访问的呢?

java程序需要通过java虚拟机栈中保存的reference数据来定位和操作java堆中的对象。由于reference在java虚拟机规范中只是规定了一个指向对象的引用,并没有定义这个引用是如何去定位和访问堆中的对象的具体位置,因此对象的访问方式也取决于虚拟机的具体实现。

目前主流的访问方式是:1)使用句柄;2)使用直接指针

句柄访问:java堆中将划分出一块内存区域作为句柄池,reference存储的则是对象的句柄地址,句柄中包含了对象的实例数据和类型数据,已经地址等信息

直接指针:reference中存储的直接就是对象在java堆中的内存地址值。

使用这两种方式各有优劣:

句柄访问最大的好处是reference中存储的句柄地址是稳定不变的,对象被移动后改变的只是句柄中的地址,reference本身是不需要改变的。

使用直接指针速度快,可以根据reference中存储的内存地址值直接找到对应的对象,避免了一次指针定位的时间开销,java中对对象的访问时非常频繁的,因此这部分开销是非常可观的。

java中常讲的基本上也是通过直接指针的方式来访问对象的,也就是栈中保存的reference记录堆中的对象的内存地址值,通过内存地址值来访问堆中的对象

参考:《深入理解Java虚拟机》

© 著作权归作者所有

共有 人打赏支持
_无问西东
粉丝 1
博文 55
码字总数 90507
作品 0
朝阳
高级程序员
私信 提问
可能是把Java内存区域讲的最清楚的一篇文章

写在前面(常见面试题) 基本问题: 介绍下 Java 内存区域(运行时数据区) Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么) 对象的访问定位的两种方式(句柄和...

Snailclimb
08/22
0
0
java JVM的内存区域(运行时数据区域)

JVM的内存形式: (1)方法区:存放了要加载的类的信息(名称,修饰符等)、类中的静态变量、类中定义为final的变量、类中Field信息、类中的方法信息,当开发人员通过Class对象的getName、i...

LCZ777
2014/11/25
0
0
深入理解Java虚拟机02--Java内存区域与内存溢出异常

一.概述   我们在进行 Java 开发的时候,很少关心 Java 的内存分配等等,因为这些活都让 JVM 给我们做了。不仅自动给我们分配内存,还有自动的回收无需再占用的内存空间,以腾出内存供其他...

ganchuanpu
08/06
0
0
JVM 虚拟机(对象创建,类加载器,执行引擎等),

1.揭开 Java 对象创建的奥秘? 2.class 文件结构详解? 3.详解 Java 类的加载过程? > Java 对象创建,class 文件结构 Java对象模型 。Java对象保存在堆内存中。在内存中,一个Java对象包含三...

desaco
08/29
0
0
Java虚拟机基础——4内存回收机制

Java虚拟机整体篇幅如下: Java虚拟机基础——1Java的内存模型 Java虚拟机基础——2JVM运行时数据区 Java虚拟机基础——3类加载机制 Java虚拟机基础——4内存回收机制 本篇文章的内容如下: ...

隔壁老李头
10/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

0015-如何使用Sentry管理Hive外部表权限

1.文档编写目的 本文档主要讲述如何使用Sentry对Hive外部表权限管理,并基于以下假设: 1.操作系统版本:RedHat6.5 2.CM版本:CM 5.11.1 3.集群已启用Kerberos和Sentry 4.采用具有sudo权限的...

Hadoop实操
25分钟前
1
0
边缘计算与数据中心的发展趋势

导读 Gartner研究表明,人工智能、物联网和5G助力下一代商业创新,由此产生大量数据,2020年前企业将使用超过75亿台联网设备。 在几乎每个方面,社会的节奏都正变得更快。我们希望客户服务问...

问题终结者
37分钟前
4
0
toString();

package com.atguigu.java1; import java.util.Date; /** * toString()的使用: * * 1.java.lang.Object类中toString()定义如下: * public String toString() { return getClass().getName......

architect刘源源
今天
1
3
不可不说的Java“锁”事

前言 Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率。本文旨在对锁相关源码(本文中的源码来自JDK 8)、使用场景进行举例,为读者介绍主流锁的知识点...

Java干货分享
今天
1
0
Java GoEasy 实现服务端推送和Web端推送

项目中需要消息推送,又想降低开发成本。Java服务器端推送,Web端接收推送信息。 具体需求: 需求一:系统框架实现全局异常捕获并录入日志表,实现实时推送消息到客户端页面展示。 需求二:系...

Gibbons
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部