大战Java虚拟机【1】—— 内存
前言
要了解Java虚拟机首先要知道的基础就是内存。虚拟机存在的意义就是对内存进行管理,因为不用人为的去管理每个对象的内存,所以才让java使用起来那么方便,不用像c、c++那样去free。
运行时数据区
Java所管理的内存划分为不同的区域,每个区域都有自己的用处。
1、程序计数器PC
如果你学过汇编的话就很好理解,在计算机中指令是一条条执行的,PC就是记住当前执行到哪一行了。需要注意的是,每条线程都需要一个独立的PC,且互相之间不影响。
2、虚拟机栈
栈是一个在程序设计的时候很常见的一个数据结构,有一定计算机基础的话,你知道递归的实现其实就是利用栈,也知道递归的深度过大会导致栈溢出。而在Java虚拟机中栈是描述Java方法执行的内存模型,每个方法的执行就是虚拟机中一个入栈出栈的过程。
3、本地方法栈
这个栈和虚拟机栈一样,只是这个栈是一个VIP,只有native方法才会使用到这个栈,那什么是native方法呢?java方法可能会调用到非java-code的方法,如c的方法,这样的方法称为native方法。
4、堆
堆是最重要的一块也是比较复杂的一块区域,因为几乎所有的对象实例都在堆里分配内存。堆是垃圾回收的主要区域,因为很多用过之后没有用的对象都在这里了,它们所占用的内存都需要被回收。
5、方法区
用于存储已经被虚拟机加载的类信息、常量、静态变量等。看到它的功能基本可以想象到,它存放的东西基本上都属于那种不可改变而且一直存在的量,所以这个区域有时被称为“永久代”但是记住它们不一定都是永久的,这个区域也会被回收,只是相对来说没有像堆那样。
对象创建
内存是用来存放对象的,那么java是如何创建一个对象的呢?首先我们知道创建一个对象就是new出来,虚拟机在new之前还要做的事情是确定这个类是否已经被正确加载了。
接下来就是去分配内存了,当类被加载完成之后,我们就知道这个对象需要多大的内存了。如果内存是完整的,那就像切蛋糕一样切出一块来,如果内存是分散的,那就需要找一块足够大的切了。而内存是分散的还是完整的取决于垃圾回收的算法。
然后设置对象的参数,如这个对象是哪个类的实例,哈希码,GC分代年龄等。
最后再执行对象的init方法给每个需要的字段进行赋值,然后根据这个对象的构造方法进行初始化。
对象的访问
那么我们创建了一个对象之后,我们如何访问这个对象呢?这个时候就用到了我们的栈了,栈记录了一个对象的引用reference。这里有两种方式,第一种是这个引用数据保存了句柄数据然后堆中有一个句柄池其中记录了对象实例数据的指针,我们通过引用找到句柄池中的位置,再通过指针找到对象。第二种是指针访问,也就是直接储存了对象的地址。句柄的好处是,对象移动时reference不用改变,指针的好处是速度快。
感受虚拟机
我们运行两个程序来直观感受一下虚拟机到底做了什么事情
首先运行下面这个程序
import java.util.ArrayList;
import java.util.List; /**
* @author LinkinStar
*/
public class T {
static class A {
} public static List<A> list = new ArrayList<>(); public static void main(String[] args) {
while (true) {
list.add(new A());
}
}
}
需要注意的是,需要调整一下虚拟机的参数

Xms是JVM初始分配的堆内存
Xms是JVM最大允许分配的堆内存
然后运行就能看见异常Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
然后在相同的条件下我们运行第二个程序
/**
* @author LinkinStar
*/
public class T {
static class A {
} public static void main(String[] args) {
while (true) {
new A();
}
}
}
你会发现没有什么异常,然后你需要做的是,对比两个程序,看看这两个程序有什么不一样,这样的不一样为什么会导致这样的结果。理解了,你就知道java虚拟机到底在做什么事情了。
上面的测试是模拟了堆溢出的情况,还有方法区溢出,常量池溢出,栈溢出等,出现StackOverflowError或者OutOfMemoryError。
我们所要知道的是出现这样错误是什么样的原因导致的,以上就是在内存方向上虚拟机相关。
大战Java虚拟机【1】—— 内存的更多相关文章
- 如何写出让java虚拟机发生内存溢出异常OutOfMemoryError的代码
程序小白在写代码的过程中,经常会不经意间写出发生内存溢出异常的代码.很多时候这类异常如何产生的都傻傻弄不清楚,如果能故意写出让jvm发生内存溢出的代码,有时候看来也并非一件容易的事.最近通过学习< ...
- 深入理解java虚拟机【内存溢出实例】
通过简单的小例子程序,演示java虚拟机各部分内存溢出情况: (1).java堆溢出: Java堆用于存储实例对象,只要不断创建对象,并且保证GC Roots到对象之间有引用的可达,避免垃圾收集器回收 ...
- 从Java虚拟机的内存区域、垃圾收集器及内存分配原则谈Java的内存回收机制
一.引言: 在Java中我们只需要轻轻地new一下,就可以为实例化一个类,并分配对应的内存空间,而后似乎我们也可以不用去管它,Java自带垃圾回收器,到了对象死亡的时候垃圾回收器就会将死亡对象的内存回 ...
- Java虚拟机:内存模型详解
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 我们都知道,当虚拟机执行Java代码的时候,首先要把字节码文件加载到内存,那么这些类的信息都存放在内存中的哪个区域呢?当我们创建一个对象实 ...
- 初识:java虚拟机的内存划分
什么是内存? 内存是计算机中的重要原件,临时存储区域,作用是运行程序.我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存.Java虚拟机要运行程序 ...
- java虚拟机的内存模型
一.为什么要了解java虚拟机的内存模型 java虚拟机作为java代码运行的平台,是java技术的基石.了解java虚拟机的内存模型也就变得十分必要.它能帮助我们更好的了解java代码的运行机制,更 ...
- java虚拟机的内存机制
我们都知道,java程序的跨平台性离不开java虚拟机,虚拟机隔绝了底层操作系统,使得java程序可以直接运行在虚拟机之上.所以,对java的学习,离不开对java虚拟机的学习与了解.下面简单整理下j ...
- Java虚拟机的内存管理
众所周知,Java程序员写的代码是没有办法控制Java对象的内存释放的,完全有JVM暗箱操作. 虽然程序员把内存的释放的任务都交给了Java虚拟机,但是并不代表Java程序就不存在内存泄漏. 反而,某 ...
- 1 - JVM随笔分类(java虚拟机的内存区域分配(一个不断记录和推翻以及再记录的一个过程))
java虚拟机的内存区域分配 在JVM运行时,类加载器ClassLoader在加载到类的字节码后,交由jvm的执行引擎处理, 执行过程中需要空间来存储数据(类似于Cpu及主存),此时的这段空间的分 ...
- JAVA虚拟机:内存各个区介绍
概述:java应用程序由java虚拟机自动管理程序执行期间内存管理. 优势:1.不再需要程序员去为使用的内存在程序中手动编写释放内存代码. 2.由虚拟机管理内存不容易出现内存泄漏和内存溢出的问题. 缺 ...
随机推荐
- mac 启动php-fpm报错 failed to open configuration file '/private/etc/php-fpm.conf': No such file or direc
直接运行,有报错找不到配置文件. $ php-fpm [11-Jan-2014 16:03:03] ERROR: failed to open configuration file '/private ...
- 深入理解CPP与C中bsearch函数的用法
·使用besearch函数的前提(一些废话) 首先让我们先亮出二分法的定义: https://baike.baidu.com/item/二分法/1364267 以及二分法实现的方法: https:// ...
- 数据库和Content Provider
SQLite提供了强大的SQL数据库的库文件,从而使应用程序拥有一个具备完全控制权的健壮的持久化层. Content Provider实现在应用程序内和应用程序之间存储.共享和使用结构化数据.通过将数 ...
- Luogu 3758 [TJOI2017]可乐(有向图邻接矩阵幂的意义 矩阵快速幂)
题目描述 加里敦星球的人们特别喜欢喝可乐.因而,他们的敌对星球研发出了一个可乐机器人,并且放在了加里敦星球的1号城市上.这个可乐机器人有三种行为: 停在原地,去下一个相邻的城市,自爆.它每一秒都会随机 ...
- 虚拟机上的Ubuntu 文件系统成为只读模式的解决办法
虚拟机环境的Linux系统由于是虚拟化虚拟出来的主机环境,因此 经常会出现一些操作系统的问题,今天我遇到了一个Ubuntu操作系统文件系统成了只读模式,无法进行系统的操作,由于出问题的主机是我个人搭建 ...
- go、java or c艹 引用的本质
在底层,引用变量由指针按照指针常量的方式实现 即一个指针常量,和一些解引用等的封装: 合到一起实现了指针这么一种形式. 用指针和引用编译到了汇编层面应该是一样的.
- mysql错误:The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement解决方法
本文为大家讲解的是mysql错误:The MySQL server is running with the --skip-grant-tables option so it cannot execut ...
- C# datatable 重新排序
DataTable table = distributionManageService.Tb_fund_withdrawaGetPageList(pagination, queryJson);//设置 ...
- 批量引用iconfont字体图标到项目
打开https://www.iconfont.cn/网址登录后选择你需要的图标添加到购物车中 点击下载代码或者添加到项目后再下载代码,再找到之前下载的的文件,拷贝到项目中
- vue项目开发时怎么解决跨域
vue项目中,前端与后台进行数据请求或者提交的时候,如果后台没有设置跨域,前端本地调试代码的时候就会报“No 'Access-Control-Allow-Origin' header is prese ...