from https://medium.com/platform-engineer/understanding-java-memory-model-1d0863f6d973

Understanding Java Memory Model is an essential learning for serious Java developers who develop, deploy, monitor, test, and tune performance of a Java application. In this blog post, we are going to discuss on Java memory model and how each part of JVM memory contributes to run our programs.

First of all, check whether you understand the following diagram of JVM architecture. If you are not familiar with it, I highly suggest you to skim through my previous post (“Java Ecosystem (Part 1): Understanding JVM Architecture“) and refresh your knowledge.

 

JVM Architecture

JVM Memory Model

You must have used some of the following JVM memory configurations when running resource-intensive Java programs.

  • -XmsSetting — initial Heap size
  • -XmxSetting — maximum Heap size
  • -XX:NewSizeSetting — new generation heap size
  • -XX:MaxNewSizeSetting — maximum New generation heap size
  • -XX:MaxPermGenSetting — maximum size of Permanent generation
  • -XX:SurvivorRatioSetting — new heap size ratios (e.g. if Young Gen size is 10m and memory switch is –XX:SurvivorRatio=2, then 5m will be reserved for Eden space and 2.5m each for both Survivor spaces, default value = 8)
  • -XX:NewRatio — providing ratio of Old/New Gen sizes (default value = 2)

But have you ever wondered how your JVM resides on memory? Let me show it. Just like any other software, JVM consumes the available space on host OS memory.

 

Host OS Memory and JVM

However, inside JVM, there exist separate memory spaces (Heap, Non-Heap, Cache) in order to store runtime data and compiled code.

1) Heap Memory

  • Heap is divided into 2 parts — Young Generation and Old Generation
  • Heap is allocated when JVM starts up (Initial size: -Xms)
  • Heap size increases/decreases while the application is running
  • Maximum size: -Xmx
 

JVM Heap Memory

1.1) Young Generation

  • This is reserved for containing newly-allocated objects
  • Young Gen includes three parts — Eden Memory and two Survivor Memory spaces (S0, S1)
  • Most of the newly-created objects goes Eden space.
  • When Eden space is filled with objects, Minor GC (a.k.a. Young Collection) is performed and all the survivor objects are moved to one of the survivor spaces.
  • Minor GC also checks the survivor objects and move them to the other survivor space. So at a time, one of the survivor space is always empty.
  • Objects that are survived after many cycles of GC, are moved to the Old generation memory space. Usually it’s done by setting a threshold for the age of the young generation objects before they become eligible to promote to Old generation.

1.2) Old Generation

  • This is reserved for containing long lived objects that could survive after many rounds of Minor GC
  • When Old Gen space is full, Major GC (a.k.a. Old Collection) is performed (usually takes longer time)

2) Non-Heap Memory

  • This includes Permanent Generation (Replaced by Metaspace since Java 8)
  • Perm Gen stores per-class structures such as runtime constant pool, field and method data, and the code for methods and constructors, as well as interned Strings
  • Its size can be changed using -XX:PermSize and -XX:MaxPermSize

JVM Non-Heap & Cache Memory

3) Cache Memory

  • This includes Code Cache
  • Stores compiled code (i.e. native code) generated by JIT compiler, JVM internal structures, loaded profiler agent code and data, etc.
  • When Code Cache exceeds a threshold, it gets flushed (and objects are not relocated by the GC).

Stack vs. Heap

So far I did not mention anything about Java Stack memory because I wanted to highlight its difference separately. First, take a look at the below image and check whether you know what’s happening here. I have already discussed on JVM Stack in my previous post.

JVM Stack, Non-Heap, and Heap (Image: jamesdbloom.com)

Anyway long story short, Java Stack memory is used for execution of a thread and it contains method specific values and references to other objects in Heap. Let’s put both Stack and Heap into a table and see their differences.

 

Here’s a nice example (from baeldung.com) on how Stack and Heap contribute to execute a simple program (Check the stack order with the code).

class Person {
int pid;
String name;// constructor, setters/getters
}public class Driver {
public static void main(String[] args) {
int id = 23;
String pName = "Jon";
Person p = null;
p = new Person(id, pName);
}
}

  

 

Stack Memory & Heap Space in Java (Image: baeldung.com)

Modifications

The above Java memory model is the most commonly-discussed implementation. However the latest JVM versions have different modifications such as introducing the following new memory spaces.

  • Keep Area — a new memory space in Young Generation to contain the most recently allocated objects. No GC is performed until the next Young Generation. This area prevents objects from being promoted just because they were allocated right before a young collection is started.
  • Metaspace — Since Java 8, Permanent Generation is replaced by Metaspace. It can auto increase its size (up to what the underlying OS provides) even though Perm Gen always has a fixed maximum size. As long as the classloader is alive, the metadata remains alive in the Metaspace and can’t be freed.

NOTE: You are always advised to go through the vendor docs to find out what works for your JVM version.

Memory Related Issues

When there is a critical memory issue, the JVM gets crashed and throws an error indication in your program output like below.

  • java.lang.StackOverFlowError — indicates that Stack Memory is full
  • java.lang.OutOfMemoryError: Java heap space — indicates that Heap Memory is full
  • java.lang.OutOfMemoryError: GC Overhead limit exceeded — indicates that GC has reached its overhead limit
  • java.lang.OutOfMemoryError: Permgen space — indicates that Permanent Generation space is full
  • java.lang.OutOfMemoryError: Metaspace — indicates that Metaspace is full (since Java 8)
  • java.lang.OutOfMemoryError: Unable to create new native thread— indicates that JVM native code can no longer create a new native thread from the underlying operating system because so many threads have been already created and they consume all the available memory for the JVM
  • java.lang.OutOfMemoryError: request size bytes for reason — indicates that swap memory space is fully consumed by application
  • java.lang.OutOfMemoryError: Requested array size exceeds VM limit– indicates that our application uses an array size more than the allowed size for the underlying platform

However, what you have to thoroughly understand is that these outputs can only indicate the impact that the JVM had, not the actual error. The actual error and its root cause conditions can occur somewhere in your code (e.g. memory leak, GC issue, synchronization problem), resource allocation, or maybe even hardware setting. Therefore, I can’t advise you to simply increase the affected resource size to solve the problem. Maybe you will need to monitor resource usage, profile each category, go through heap dumps, check and debug/optimize your code etc. And if none of your efforts seems to work and/or your context knowledge indicates that you need more resources, go for it.

What’s Next

During my undergraduate research on JVM performance aspects, we found several approaches used by the industry to minimize the impact of performance faults like memory errors. Let’s discuss about Java Performance Management in-depth very soon. In the meantime, read the next blog post of this series in which I explain how Java Garbage Collection really worksunder the hood. Stay excited with this blog for more exciting posts!


Be sure to follow me on Twitter @ashen_wgt and send me your feedback, comment any questions you have, let me know your suggestions and I’ll surely check it out/retweet! You can also share this post with your friends and check my other articles on PlatformEngineer.com


References

Understanding Java Memory Model-理解java内存模型(JVM)的更多相关文章

  1. JAVA内存模型(Java Memory Model ,JMM)

    http://blog.csdn.net/hxpjava1/article/details/55189077 JVM有主内存(Main Memory)和工作内存(Working Memory),主内存 ...

  2. 并发研究之Java内存模型(Java Memory Model)

    Java内存模型JMM java内存模型定义 上一遍文章我们讲到了CPU缓存一致性以及内存屏障问题.那么Java作为一个跨平台的语言,它的实现要面对不同的底层硬件系统,设计一个中间层模型来屏蔽底层的硬 ...

  3. java内存模型(Java Memory Model)

    内容导航: Java内存模型 硬件存储体系结构 Java内存模型和硬件存储体系之间的桥梁: 共享对象的可见性 竞争条件 Java内存模型规定了JVM怎样与计算机存储系统(RAM)协调工作.JVM是一个 ...

  4. java学习:JMM(java memory model)、volatile、synchronized、AtomicXXX理解

    一.JMM(java memory model)内存模型 从网上淘来二张图: 上面这张图说的是,在多核CPU的系统中,每个核CPU自带高速缓存,然后计算机主板上也有一块内存-称为主内(即:内存条).工 ...

  5. java 深入理解jvm内存模型 jvm学习笔记

    jvm内存模型 这是java堆和方法区内存模型 参考:https://www.cnblogs.com/honey01/p/9475726.html Java 中的堆也是 GC 收集垃圾的主要区域.GC ...

  6. 当我们在谈论JMM(Java memory model)的时候,我们在谈论些什么

    前面几篇中,我们谈论了synchronized.final以及voilate的用法和底层实现,都绕不开一个话题-Java内存模型(java memory model,简称JMM).Java内存模型是保 ...

  7. 死磕 java同步系列之JMM(Java Memory Model)

    简介 Java内存模型是在硬件内存模型上的更高层的抽象,它屏蔽了各种硬件和操作系统访问的差异性,保证了Java程序在各种平台下对内存的访问都能达到一致的效果. 硬件内存模型 在正式讲解Java的内存模 ...

  8. Java原子性、可见性、内存模型

    原子性: 原子性就是指该操作是不可再分的.不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作.简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性.比如 a = ...

  9. java提高篇-----理解java的三大特性之封装

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

随机推荐

  1. 用Navicat连接mysql报错:2003-Can't connect to MySql server on '10.100.0.109'(10039)

    问题描述 在 window 系统上,用 Navicat 连接 Mysql 数据库,弹出以下提示 问题原因  Mysql 数据库未启动 解决方案:启动 Mysql 数据库 1.点击桌面左下角运行 cmd ...

  2. IntelliJ IDEA 2019.1.3 最新破解教程【最强 可用至2099年】

    本文包括最新[2019.1.2]安装 和[2018.3.2](推荐)安装 ①IntelliJ IDEA 2018.3.2安装永久安装[最强]  一. 在官网下载IDEA安装包  链接:https:// ...

  3. mysql 数据库基础操作

    一 知识储备 MySQL数据库基本操作知识储备 数据库服务器:一台计算机(对内存要求比较高) 数据库管理系统:如mysql,是一个软件 数据库:oldboy_stu,相当于文件夹 表:student, ...

  4. navicat连接mysql查询结果中文都是?号(C#)

    记录解决方法,方便以后查看.  有几个地方需要注意: 1.连接mysql数据库的字符串最后加上Charset=utf8; 2.mysql中character_set_XX设置都为utf8,使用show ...

  5. 【Unity|C#】基础篇(8)——委托(Delegate)/ 事件(Event)

    [学习资料] <C#图解教程>(第13~14章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.bai ...

  6. mybatis(五):源码分析 - sqlsession执行流程

  7. python:创建文件夹

    #!/usr/bin/python# -*- coding:utf-8 -*- import os dir = './dir'os.mkdir(dir)

  8. 巨杉Tech | SparkSQL+SequoiaDB 性能调优策略

    当今时代,企业数据越发膨胀.数据是企业的价值,但数据处理也是一种技术挑战.在海量数据处理的场景,即使单机计算能力再强,也无法满足日益增长的数据处理需求.所以,分布式才是解决该类问题的根本解决方案.而在 ...

  9. vector,list不是模板

    vector和list在命名空间std里,还需要添加声明 using namespace std;   或者 std::list 也可以.

  10. AM335X的SD卡更新系统学习记录

    一般利用一张SD卡就能进行系统的更新,以前一直不知是什么原理,最近了解了下,对了解到的内容做个记录.使用的是AM335X平台,系统是Linux,文件系统是EXT3: 1.首先需要一张分好分区的SD卡( ...