前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >理解linux平台上java程序的内存模型

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

作者头像
qsjs
发布2020-06-09 10:44:33
9230
发布2020-06-09 10:44:33
举报

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.
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • java 永久代(java程序的代码区和数据区) + java 堆(新生代 和 老年代) + java 线程栈空间大小+ NIO
  • 如果系统内存明显足够,但是依然大量使用 swap,其中的一种可能是: NIO的buffer 回收不及时,导致pagecache 空间不足,而pagecache不足的情况下,如果依然有很多的NIO 访问,那么必然导致需要导致大量使用swap.
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档