Java 内存模型(一)
打算花比较长的篇幅来描述下自己理解的JVM,尽量描述的清晰易懂一些,从简单慢慢到慢慢深入,一方面自己也复习一下,一方面也供大家参考,少走些弯路。鉴于本人水平有限,如有错误的地方,欢迎指出,感谢。
一段废话引出,大家都知道java有JVM,那JVM有个非常方便的自动内存管理机制,致使java开发人员不再需要为每个new操作去写配对的delete/free代码,而且不容易出现内存泄漏和内存溢出的问题(不容易并非不可能),不过真因为此一旦出现了内存泄漏或者溢出的问题,如果不了解JVM怎么样使用内存的,那么排查起来也会比较困难。
我们初始学习java时候很多人关注就是java的堆栈,这种分法比较粗糙,但是易与理解,实际上远远不止于此,但是今天我们就先按粗浅的方式去解释下,后面我们在逐步深入。按我的习惯,我们先看个例子。
public class BaseTest {
public static void main(String[] args) throws Exception{
ArrayList list=new ArrayList();
while(true){
list.add(new FinalBean());
}
}
}
上面这段代码最终的结果:
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid1288.hprof ...
Heap dump file created [34835053 bytes in 0.247 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.String.concat(String.java:2032)
at com.cz.smart.center.FinalBean.<init>(FinalBean.java:13)
at com.cz.smart.center.BaseTest.main(BaseTest.java:14)
为什么会出现这种结果呢?
我们通过创建实例对象 new FinalBean(),会开辟堆内存空间,往list列表里面加,导致实例对象没法回收,一直到无法申请到新的内存,导致爆内存溢出,那有没有考虑过,为什么实例对象的内存无法进行回收呢?
再看一个例子
public class BaseTest {
int i = 0;
public static void main(String[] args) throws Exception{
BaseTest b = new BaseTest();
b.addStackLength();
} public void addStackLength(){
i++;
System.out.println(i);
addStackLength();
}
}
上面这段代码最终的结果:
938
939
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.UTF_8.updatePositions(UTF_8.java:77)
at sun.nio.cs.UTF_8.access$200(UTF_8.java:57)
at sun.nio.cs.UTF_8$Encoder.encodeArrayLoop(UTF_8.java:636)
at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
at java.io.PrintStream.write(PrintStream.java:526)
at java.io.PrintStream.print(PrintStream.java:597)
at java.io.PrintStream.println(PrintStream.java:736)
为什么这段代码会报这个错呢?StackOverflowError 栈溢出错误。
递归调用,死循环,超过栈的深度,导致抛出异常,那这段代码再内存从怎么跑的呢?我画图解释下:
我们知道栈是线程独享的,每个线程都会有自己独立的栈,而每调用一个方法会产生一个栈针进行入栈。
1.在代码b.addStackLength 时候,会入栈addStackLength方法的栈针,栈针包括局部变量表,操作数栈,动态链接,方法出口等信息(这些后面会详细讲解)。
2.进入方法addStackLength的时候,先执行i++,然后输出i++信息,发现该方法又调用了addStackLength的方法。
3.于是又会入栈一个addStackLength方法的栈针,以此循环,由于是死循环,入栈的栈针超过了栈的深度,抛出StackOverflowError 错误。
注:如果是递归调用而没有死循环,那情况就是在最底层的方法执行完之后,最底层方法就会出栈,调转到上一个调用该方法的下一行,以此类推持续出栈,这就是栈的先入后出。
后续一步步拆分堆和栈内容信息,未完待续。。。
Java 内存模型(一)的更多相关文章
- JVM学习(3)——总结Java内存模型
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 为什么学习Java的内存模式 缓存一致性问题 什么是内存模型 JMM(Java Memory Model)简 ...
- 浅析java内存模型--JMM(Java Memory Model)
在并发编程中,多个线程之间采取什么机制进行通信(信息交换),什么机制进行数据的同步? 在Java语言中,采用的是共享内存模型来实现多线程之间的信息交换和数据同步的. 线程之间通过共享程序公共的状态,通 ...
- JMM(java内存模型)
What is a memory model, anyway? In multiprocessorsystems, processors generally have one or more laye ...
- 《深入理解Java内存模型》读书总结
概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...
- Java内存模型深度解析:final--转
原文地址:http://www.codeceo.com/article/java-memory-6.html 与前面介绍的锁和Volatile相比较,对final域的读和写更像是普通的变量访问.对于f ...
- Java内存模型深度解析:volatile--转
原文地址:http://www.codeceo.com/article/java-memory-4.html Volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特 ...
- Java内存模型深度解析:顺序一致性--转
原文地址:http://www.codeceo.com/article/java-memory-3.html 数据竞争与顺序一致性保证 当程序未正确同步时,就会存在数据竞争.java内存模型规范对数据 ...
- Java内存模型深度解析:基础部分--转
原文地址:http://www.codeceo.com/article/java-memory-1.html 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何 ...
- 深入理解java内存模型系列文章
转载关于java内存模型的系列文章,写的非常好. 深入理解java内存模型(一)--基础 深入理解java内存模型(二)--重排序 深入理解java内存模型(三)--顺序一致性 深入理解java内存模 ...
- Java内存模型深度解读
Java内存模型规范了Java虚拟机与计算机内存是如何协同工作的.Java虚拟机是一个完整的计算机的一个模型,因此这个模型自然也包含一个内存模型——又称为Java内存模型. 如果你想设计表现良好的并发 ...
随机推荐
- stm32 奇怪的位赋值问题 出错了
转载请注明出处:http://blog.csdn.net/qq_26093511/article/category/6094215 1.在51单片机里 ,下面这两种操作方法都是一样的,没有什么问题! ...
- uboot和内核分区的修改
随着内核的更新,内核越来越大,uboot给nand的kernel分区默认是2M的 device nand0 <nandflash0>, # parts = 4 #: name ...
- VisualGDB系列5:使用VS来开发Linux程序
根据VisualGDB官网(https://visualgdb.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指正. 本文演示如何使用VS来构建和调试Linu ...
- <%@ include file=""%>与<jsp:include page=""/>两种方式的作用
一.前言 身为一名coder有太多太多的知识点要去学,太多太多的东西要去记.往往一些小细节也就难免疏忽,但悲催的是多数困恼你的bug就是因为这些微不足道的知识点.我们又不是机器人,怎么可能什么都记得了 ...
- nginx gzip
# 开启gzip gzip on; # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩 gzip_min_length 1k; # gzip 压缩级别,1-10,数字越大压缩的越好,也 ...
- mysql中有多少种日志
Mysql的日志包括如下几种日志: 错误日志 普通查询日志 二进制日志 慢查询日志 Mysql版本 此文档测试mysql的版本为 mysql -V 错误日志 error log Mysql错误日志主要 ...
- 想以编程为职业,现在正在看毕向东的java基础,接下来应该看什么视频,求前辈们指教。
想以编程为职业,现在正在看毕向东的java基础,接下来应该看什么视频,求前辈们指教. https://zhidao.baidu.com/question/1368482680246425699.htm ...
- 20. Linux提权:从入门到放弃
几点前提 已经拿到低权shell 被入侵的机器上面有nc,python,perl等linux非常常见的工具 有权限上传文件和下载文件 内核漏洞提权 提到脏牛,运维流下两行眼泪,我们留下两行鼻血.内核漏 ...
- Algorithms - Fibonacci Number
斐波那契数列(Fibonacci Number)从数学的角度是以递归的方法定义的: \(F_0 = 0\) \(F_1 = 1\) \(F_n = F_{n-1} + F_{n-2}\) (\(n \ ...
- .net Core命令行,Json配置
创建.netCore控制台 NuGet :Microsoft.AspNetCore.All static void Main(string[] args) { var builder = new Co ...