深入理解java虚拟机(一)-----java内存区域以及内存溢出异常
概述
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内存区域以及内存溢出异常的更多相关文章
- 深入理解java虚拟机系列(一):java内存区域与内存溢出异常
文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...
- 深入理解Java虚拟机之Java内存区域与内存溢出异常
Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...
- 深入理解Java虚拟机之图解Java内存区域与内存溢出异常
Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...
- 深入理解Java虚拟机之Java内存区域随笔
1.java内存区域与内存溢出异常 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域:1.程序计数器,2.栈(虚拟机栈和本地方法栈 ),3.堆,4.方法区(包含 ...
- 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常
第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域
- 深入理解java虚拟机-第二章:java内存区域与内存泄露异常
2.1概述: java将内存的管理(主要是回收工作),交由jvm管理,确实很省事,但是一点jvm因内存出现问题,排查起来将会很困难,为了能够成为独当一面的大牛呢,自然要了解vm是怎么去使用内存的. 2 ...
- 深入理解Java虚拟机(1)--Java内存区域
运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用 ...
- 深入理解java虚拟机---->java内存区域与内存溢出异常
2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...
- 《深入理解Java虚拟机》之(一、内存区域)
一.java的体系构成: Java的技术体系主要由支撑java程序运行的虚拟机.提供各种开发领域接口支持的java api.java编程语言及许多第三方java框架(如Spring .Struts等) ...
- 深入了解Java虚拟机(1)java内存区域与内存溢出异常
java内存区域与内存溢出异常 一.运行时数据区域 1.程序计数器:线程私有,用于存储当前所执行的指令位置 2.Java虚拟机栈:线程私有,描叙Java方法执行模型:执行方法时都会创建一个栈帧,存储局 ...
随机推荐
- 开启mysql-binlog日志操作步骤
步骤1:找到mysql主库的配置文件(注意:不能为从库),lunix系统路径一般为/etc/my.cnf 步骤2:修改配置文件(可以提前备份一下)以开启mysql-binlog功能.添加以下3行: l ...
- 解决easyUI中翻页后前面已钩选项自动变为未选择的问题
在easyUI的datagrid中,必须在属性的第一条就要写 idField:'id' (只要创建数据表格,就必须要加idField),其中id是页面数据的主键名称. 这样设置之后,表格翻页之后,前面 ...
- openstack使用openvswitch实现vxlan的方法
openstack使用openvswitch实现vxlan,分享给大家,具体如下: openstack环境: 1 版本:ocata 2 系统:ubuntu16.04.2 3 控制节点 1个 + 计算节 ...
- CodeForces - 864C-Bus-(模拟加油站问题)
https://vjudge.net/problem/CodeForces-864C 题意:两地之间有个加油站,往返走k个单程,最少加油多少次. 大佬几十行代码就解决,我却要用一百多行的if语句模拟解 ...
- R语言-时间序列图
1.时间序列图 plot()函数 > air<-read.csv("openair.csv") > plot(air$nox~as.Date(air$date,& ...
- 史上最全最详细的环境搭建教程,行百里者手把手教你在windows下搭建Anaconda+pycharm+库文件(TensorFlow,numpy)环境搭建
我是在搭建TensorFlow开发环境的道路上走了很多弯路 掉了很多头发,为了让广大同学们不在受苦受累 下面我将手把手教你学习如特快速搭建python环境 快速导入numpy,PIL,pillow,等 ...
- ABAP 程序/接口调用其他程序的数据
在ABAP遇到的业务场景中,可能会遇到一种情况,需要调用其他报表的数据来发送或者二次加工,这个时候又不想对源程序做大的改动.有以下几种思路解决. 1.修改源程序,将需要展示的数据存储到DB中,然后主程 ...
- zip 格式解析
1.格式 https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.2.0.txt 官方文档 https://blog.csdn.net/hp9103 ...
- ES6学习笔记(函数)
1.函数参数的默认值 ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面. function log(x, y = 'World') { console.log(x, y); } log(' ...
- sql yog出现2013错误
首先用telnet检查一下你的防火墙端口,如果连接失败,配置防火墙. 配置防火墙,开启3306端口 find -name iptables vim /etc/sysconfig/iptables -A ...