Java中哪些组件需要使用内存-知了汇智

Java中哪些组件需要使用内存

  Java启动后也作为一个进程运行在操作系统中,那么这个进程有哪些部分需要分配内存空间呢?

  Java堆

  Java堆是用于存储Java对象的内存区域,堆的大小在JVM启动时就一次向操作系统申请完成,通过-Xmx和-Xms两个选项来控制大小,Xmx表示堆的最大大小,Xms表示初始大小。一旦分配完成,堆的大小就将固定,不能在内存不够时再向操作系统重新申请,同时当内存空闲时也不能将多余的空间交还给操作系统。

  在Java堆中内存空间的管理由JVM来控制,对象创建由Java应用程序控制,但是对象所占的空间释放由管理堆内存的垃圾收集器来完成。根据垃圾收集(GC)算法的不同,内存回收的方式和时机也会不同。
Java中哪些组件需要使用内存

 

  线程

  JVM运行实际程序的实体是线程,当然线程需要内存空间来存储一些必要的数据。每个线程创建时JVM都会为他创建一个堆栈,堆栈的大小根据不同的JVM实现而不同,通常在256KB~756KB之间。

  线程所占空间相比堆空间来说比较小。但是如果线程过多,线程堆栈的总内存使用量可能也非常大。当前有很多应用程序根据CPU的核数来分配创建的线程数,如果运行的应用程序的线程数量比可用于处理他们的处理器数量多,效率通常很低,并且可能导致比较差的性能和更高的内存占用率。

  类和类加载器

  在Java中类和加载类的类加载器本身同样需要存储空间,在Sun JDK中他们也被存储在堆中,这个区域叫做永久代(PermGen区)。

  需要注意的一点是JVM是按需来加载类的,曾经有个疑问:JVM如果要加载一个jar包是否把这个jar包中的所有类都加载到内存中?显然不是的。JVM只会加载那些在你的应用程序中明确使用的类到内存中。要查看JVM到底加载了哪些类,可以在启动参数上加上-verbose:class。

  理论上使用的Java类越多,需要占用的内存也会越多,还有一种情况是可能会重复加载同一个类。通常情况下JVM只会加载一个类到内存一次,但是如果是自己实现的类加载器会出现重复加载的情况,如果PermGen 区不能对已经失效的类做卸载,可能会导致PermGen区内存泄漏。所以需要注意PermGen区的内存回收问题。通常一个类能够被卸载,有如下条件需要被满足。

  在Java堆中没有对表示该类加载器的java.lang.ClassLoader对象的引用。

  Java堆没有对表示类加载器加载的类的任何java.lang.Class对象的引用。

  在Java堆上该类加载器加载的任何类的所有对象都不再存活(被引用)。

  需要注意的是,JVM所创建的3个默认类加载器Bootstrap ClassLoader、ExtClassLoader和AppClassLoader都不可能满足这些条件,因此,任何系统类(如java.lang.String)或通过应用程序类加载器加载的任何应用程序类都不能在运行时释放。

  NIO

  Java在1.4版本以后添加了新I/O(NIO)类库,引入了一种基于通道和缓冲区来执行I/O的新方式。就像在Java堆上的内存支持I/O缓冲区一样,NIO使用java.nio.ByteBuffer.allocateDirect()方法分配内存,这种方式也就是通常所说的NIO direct memory。ButeBuffer.allocateDirect()分配的内存使用的是本机内存而不是Java堆上的内存,这也进一步说明每次分配内存时调用操作系统os::malloc()函数。另外一方面直接ByteBuffer产生的数据如果和网络或者磁盘交互都在操作系统的内核空间中发生,不需要将数据复制到Java内存中,很显然执行这种I/O操作要比一般的从操作系统的内核空间到Java堆上的切换操作快很多,因为他们可以避免在Java堆与本机堆之间复制数据。如果你的I/O频繁的发送很小的数据,这种系统调用的开销可能会抵消数据在内核空间和用户空间复制带来的好处。

  直接ByteBuffer对象会自动清理本机缓存区,但这个过程只能作为Java堆GC的一部分来执行,因此他们不会自动响应施加在本机堆上的压力。GC仅在Java堆被填满,以至于无法为堆分配请求提供服务时发生,或者在Java应用程序中显示请求时发生。当前在很多NIO框架中都在代码中显式的调用System.gc()来释放NIO持有的内存。但是这种方式会影响应用程序的性能,因为会添加GC的次数,一般情况下通过设置-XX:+DisableExplicitGC来控制System.gc()的影响,但是又会导致NIO direct memory内存泄漏问题。

  JNI

  JNI技术使得本机代码(如C语言程序)可以调用Java方法,也就是通常所说的native memory。实际上Java运行时本身也依赖于JNI代码来实现类库功能,如文件操作、网络I/O操作或者其他系统调用。所以JNI也会增加Java运行时的本机内存占用。

          版权声明:本文来源于网络,由知了堂搜集整理,仅供大家学习

项目教学·项目驱动

132 2811 3191
预约免费试学
点击咨询
预约试学