概述

Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。

一、运行时数据区域

在java程序执行的过程中,jvm会把它所管理的内存区域划分为不同的数据区域,因为在计算机中,操作系统是老大,操作系统分配一定的内存给到jvm,jvm就是一个小家庭,拿到了土地了,比如这块呢做房子,那块种菜园,后面一块做池塘。。这样每块地都互不干扰,也都有自己的用途。如图:

红框区域代表是所有线程共享的区域,绿色区域则非线程共享,每个线程都自己管理这些数据区域。

1、堆

大部分的java项目中,堆内存都是最大的,因为堆的唯一目的就是存放对象实例,包含所有的对象以及数组都存放在这里。但是随着JIT编译器的发展,这一点也不是那么绝对了,这点以后再介绍,当前可以认为所有对象都存放在堆内存中。

另外堆中内存还可以细分:Eden、From Survivor、To Survivor、Old Generation,前三者属于新生代,最后一个则是老年代。

2、栈

在java中,栈分为虚拟机栈以及本地方法栈。是java程序方法执行时的内存模型,当执行到一个方法时,栈中就会创建一个栈帧,如图所示:

本地方法栈与虚拟机栈的作用非常类似,只是虚拟机栈执行的是java方法,本地方法栈执行的是native方法。

3、程序计数器

是一块较小的内存区域,可以看做是当前线程所执行的字节码的行号指示器。字节码解释器就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

4、方法区

用于存储已被虚拟机加载的类信息、常量(放入运行时常量池)、静态变量、即时编译器编译后的代码等数据。说到运行时常量池,string很有发言权,当声明String s = "虚拟机";首先自然是创建一个string对象放在堆中,另外会把"虚拟机"字符串放入到

运行时常量池,可以理解成缓存,不明白的可以看走进JDK(二)------String

另外值得一提的就是直接内存,这块内存不归jvm管理,但是在nio中使用到,可以使用native函数库直接分配堆外内存,然后通过一个存储在堆中的DirectByteBuffer对象作为这块内存的引用进行操作。拿nio来说,这种操作能够大大提高性能,因为避免了在java堆和native堆中来回复制数据。

二、对象创建过程

当我们new xxx()时,可曾想过背后到底发生了什么? 看图:

三、对象内存布局

对象在内存中存储的布局主要分为三块:对象头、实例数据和对齐补充。
对象头:
1、用于存储对象自身运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
2、另一部分是类型指针,即对象指向它的类元数据的指针,迅疾通过这个指针来确定这个对象时哪个类的实例。
实例数据:对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。父类继承下来的字段,也会在子类中存储。
对齐补充:仅仅起着占位符的作用。主要是因为jvm要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍,所以当实例数据部分没有对齐时,就需要通过对齐填充来补全。

四、对象的访问定位 

对象创建好了之后,如何使用对象呢?通过栈上的reference数据来操作堆上的具体对象,主流的访问方式有句柄和直接指针两种:

1、句柄

优点:当对象移动的时候(垃圾回收的时候移动很普遍),这样值需要改变句柄中的指针,但是栈中的指针不需要变化,因为栈中存储的是句柄的地址
缺点:需要进行二次定位,寻找两次指针,开销相对于更大一些

2、直接指针

优点:速度快,不需要和句柄一样指针定位的开销

对于sun hotspot虚拟机来说,使用的是第二种方式。

五、OutOfMemoryError与StackOverflowError

1、OutOfMemoryError:

各内存区域中,栈、堆、方法区、直接内存都有可能抛出此异常。

栈:当虚拟机栈可以动态扩展时,无法申请到足够的内存时,就会抛出此异常。

while(true) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while(true) { }
}
});
thread.start();
}

堆:当堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出此异常。

List list = new LinkedList();
while(true) {
list.add(student);
}

方法区:当方法区无法满足内存分配需求时,将抛出此异常。

2、StackOverflowError:

线程请求的栈深度大于虚拟机所允许的深度,将会抛出此异常。

这么说估计很多人都不明白,来个示例:

。。。main() {
method()
}
//method()不停的调用自己,此时就会出现StackOverflowError
void method() {
method()
}

深入理解java虚拟机(一)-----java内存区域以及内存溢出异常的更多相关文章

  1. 深入理解java虚拟机系列(一):java内存区域与内存溢出异常

    文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...

  2. 深入理解Java虚拟机之Java内存区域与内存溢出异常

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...

  3. 深入理解Java虚拟机之图解Java内存区域与内存溢出异常

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...

  4. 深入理解Java虚拟机之Java内存区域随笔

    1.java内存区域与内存溢出异常 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域:1.程序计数器,2.栈(虚拟机栈和本地方法栈 ),3.堆,4.方法区(包含 ...

  5. 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域  

  6. 深入理解java虚拟机-第二章:java内存区域与内存泄露异常

    2.1概述: java将内存的管理(主要是回收工作),交由jvm管理,确实很省事,但是一点jvm因内存出现问题,排查起来将会很困难,为了能够成为独当一面的大牛呢,自然要了解vm是怎么去使用内存的. 2 ...

  7. 深入理解Java虚拟机(1)--Java内存区域

    运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用 ...

  8. 深入理解java虚拟机---->java内存区域与内存溢出异常

    2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...

  9. 《深入理解Java虚拟机》之(一、内存区域)

    一.java的体系构成: Java的技术体系主要由支撑java程序运行的虚拟机.提供各种开发领域接口支持的java api.java编程语言及许多第三方java框架(如Spring .Struts等) ...

  10. 深入了解Java虚拟机(1)java内存区域与内存溢出异常

    java内存区域与内存溢出异常 一.运行时数据区域 1.程序计数器:线程私有,用于存储当前所执行的指令位置 2.Java虚拟机栈:线程私有,描叙Java方法执行模型:执行方法时都会创建一个栈帧,存储局 ...

随机推荐

  1. Navicat Premium 12激活教程

    Navicat Premium 12激活教程 1.软件包的下载 百度云地址链接: 注册机:https://pan.baidu.com/s/1KzmCbVYcVoXt_t4osXk3Kw  提取码: q ...

  2. R数据导入导出(一): read.table()和read.csv()的区别

    之前也参考过一些资料,虽然是这么简单的两个buildin,还是仔细对比了一下,我有两张txt,都是从cube中导出的,就意味着每一列的列数是不一样的.R语言官方文档中有这样一句话不知道大家注意到了没有 ...

  3. React16的interactiveUpdates

    交互式更新是用户交互的结果. 它们比默认的非交互式更新(如服务器事件)具有更高的优先级. 异步模式下交互式更新的特殊之处在于,一次交互式更新可能会影响后续行为. 例如,一个表单字段上的"提交 ...

  4. fopen特殊模式r+, w+, a+辨析

    fopen模式分两大类,即 TEXT模式:r, w, a, r+, w+, a+ BIN模式:rb, wb, ab, r+b, w+b, a+b 模式 读指针初始位置 写指针初始位置 模式用途 详细说 ...

  5. 谈谈你对spring的理解?

    spring么,就是春天了.春天,动物.....不可描述的季节……你懂得!!! 希望这么说能把面试官逗乐吧. spring可以实现java模块化开发,贯穿表现层,业务层,逻辑层,实现了各个层之间的解耦 ...

  6. Java 定时任务的几种实现方式

    JAVA实现定时任务的几种方式 @(JAVA)[spring|quartz|定时器]  近期项目开发中需要动态的添加定时任务,比如在某个活动结束时,自动生成获奖名单,导出excel等,此类任务由于活动 ...

  7. 其他封装ui的平台

      mint平台 http://mint-ui.github.io/#!/zh-cn

  8. winform UI 设计方法

    这里主要提供了一种设计思路,你可以将成套的UI图像添加或替换到本程序中.在设计过程中,还存在许多疏漏,懒得仔细修改了,在使用过程中自行修改添加.这里的函数基本上都可以单独使用,需要哪个将cs文件加入到 ...

  9. mysql-----04 多表查询

    本节主要介绍mysql的多表查询(多表连接查询.复合条件查询.子查询) 一.多表连接查询 #重点:外链接语法 select 字段列表 from 表1 inner|left|right join 表2 ...

  10. pwnable.kr-random-witeup

    看源代码. 可知,在linux下生成个随机数在于输入数异或等于固定值即可,而且吧, 随机数是固定的. 先得出随机数. random=1804289383 OK,接下来用计算器异或就行啦.0xB526F ...