专栏首页MyPanda的学习笔记理解linux平台上java程序的内存模型

理解linux平台上java程序的内存模型

java 程序是运行在jvm 虚拟机里面的,离开jvm虚拟机,那么java程序无法直接在linux平台的运行。 所以java应用程序和os 平台之间是隔着jvm虚拟机的。 所谓的jvm虚拟机,本质上就是一个进程,此时它的内存模型和普通的进程有相同之处,但它又是java程序的管理者,所以它又有自己独特的内存模型. 从os层面来看jvm的进程,其内存模型包含如下几个部分: 内核内存 + jvm的code + jvm的data + jvm的 heap + jvm的stack + unused memory. 其中的heap, stack 就是我们常说的“堆栈” 空间. 我们更多需要从jvm作为java程序管理者的角度来看其内存模型: 此时jvm的内存空间可以分为两大类,分别是 “堆内存” 以及“非堆内存”,其中前者是可以分配给java程序使用的,而后者则是jvm进程自己使用的。 所以“堆内存”是我们要讨论的重点:

A. “堆内存”的大小是通过如下两个参数控制的: -Xms , 这个是jvm启动时候的初始堆大小. -Xmx, 这个是jvm最大允许分配的堆内存大小. jvm进程会根据 可用堆空间的大小,动态调整jvm的堆大小,但是最大不超过Xmx设置的值,当然也会减小堆空间的大小,最小为Xms设置的值;如果设置的Xms 大于 Xmx, 那么可能会导致java程序无法正常启动,通常情况下,设置Xms 和Xmx 一样大小,以避免jvm频繁调整堆的大小. jvm进程不仅仅提供了java程序的运行环境,同时还进行 java 程序的内存回收工作(也就是GC操作),程序员从而可以不用考虑内存回收,这个是jvm进程(也就是java虚拟机)来完成的.

B. GC 过程的理解: 在jvm进行GC的时候,会遍历所有已经分配的堆空间里的对象,从而判断是否可以进行内存回收, 如果这时候有一部分数据已经在SWAP空间上,那么就需要把这部分数据交换回内存,而如果内存本就不够,就需要把堆空间中的另一部分给交换到swap中,这时候可能发生的最坏的情况是:堆中的对象被全部交换到swap中,然后再swap到堆中. 而Linux的swap回收是具有滞后性的,所以可能看到swap的空间被大量使用. 同时会经历系统响应缓慢的情况.

C. java程序的NIO: 通常情况下,应用进程不直接访问内核内存,而是通过操作系统作为一个中介层实现和内核的交互,但是随着对性能的追求,特别是为了解决高并发的性能问题,在java里面有了一种叫做NIO(Non-blocking IO)的的访问方式,比较NIO 和原始IO的区别: 原始IO是面向流的,每次从流中读取一个或多个字节直至读取所有字节,没有缓存这些数据,这就意味着当一个线程调用read或者write方法的时候,线程处于阻塞状态直到io 操作完成. 当并发非常高的时候,就会出现明显的问题. NIO是面向缓冲的,有一个通道channel 和这个缓冲区buffer 相对应;读取的时候,访问通道channel来获得缓冲区buffer的数据,通道channel支持异步读写数据,这样线程无需等待IO操作的完成,从而解决了线程读操作的阻塞问题. 在数据写入的时候,向channel 写入数据就可以了,因为支持异步IO读写,所以也无需等待写入的完成,所以在数据写入的时候也解决了阻塞的问题. 另外,通道channel 支持同时进行读写操作,而流仅仅支持单向的读或者写. 另外,磁盘数据和缓冲区之间通常是采用“块操作”,这个效率也比流式操作高的多, 当IO操作完成后,缓冲区Buffer会被释放,以便再次使用。 和流式比起来,缺点是: 需要使用缓冲区,也就是需要消耗一定的内存资源, 而流操作则不需要缓冲区, java 的NIO使用的内存区域是内核内存的system 区和PageCache区

D. java占用空间大小计算: java 程序是在jvm里面运行的,所以java 程序占用的内存大小理论上不会超过 JVM的 堆大小,主要包含以下部分:

java 永久代(java程序的代码区和数据区) + java 堆(新生代 和 老年代) + java 线程栈空间大小+ NIO

其中jvm配置的"堆"大小的最大值,就是: "java 永久代+java 新生代+java 老年代" 的最大值

默认情况下,每个java线程 stack的大小为1M, 所以java线程栈大小和线程数量多少有关,这部分内存不属于jvm管理的内存

NIO的大小,如果java 大量使用NIO, 这个值就会比较大,要通过监控工具查看其大小, 这部分内存属于内核内存的System 区和PageCache区域。

如果系统内存明显足够,但是依然大量使用 swap,其中的一种可能是: NIO的buffer 回收不及时,导致pagecache 空间不足,而pagecache不足的情况下,如果依然有很多的NIO 访问,那么必然导致需要导致大量使用swap.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • pycharm 入门基础配置

    pycharm是python的IDE 工具,这个工具很强大,之所以强大,所以对于其配置也可以很复杂,作为一个pycharm的小白,以下的基本的使用是必需的,然后...

    qsjs
  • 编译、链接到载入、运行的大致过程----4.运行

    根据前面所述,可执行文件的type=LOAD的segment才会被装载,但是并不会把所有的data和code都加载到内存,因为这样浪费空间也没有必要;装载的时候...

    qsjs
  • dockerfile常用易混指令--(2)

    接上一篇:<<dockerfile 常用易混指令--(1)>>, 本篇介绍剩余的几个基础指令:

    qsjs
  • SAP ABAP SM50事务码和Hybris Commerce的线程管理器

    Jerry Wang
  • ArrayList源码分析(基于jdk1.8)(二):subList陷阱补充

    关于ArrayList的subList方法,还会出现另外一个问题就是强引用释放问题。看如下案例:

    冬天里的懒猫
  • Web基础配置篇(一): Java环境配置

    href="https://jq.qq.com/?_wv=1027&k=52sgH1J"

    品茗IT
  • ehcache报错

    jfinal2.0+tomcat7+ehcache2.6.11+Linux Linux version 2.6.18-164.el5 (mockbuild@x8...

    Ryan-Miao
  • Java入门知识大全

    说起来,在大学里面我学过的编程语言只有c++和java。这其中c++是作为必修课学的,而java是作为选修课学的。至于后面的c、汇编、python、js...

    良月柒
  • 将Linux默认的OpenJDK替换为Oracle JDK

    经查可能是与系统自带的OpenJDK有关,解决方案是将系统自带的OpenJDK更新为Oracle的JDK。

    大江小浪
  • 列举Java中常用的包、类和接口

      javax.servlet    org.apache.struts.action

    Kevin_Zhang

扫码关注云+社区

领取腾讯云代金券