Java 启动后也作为一个进程运行在操作系统中,那么这个进程有哪些部分需要分配内
存空间呢?
Java 堆
Java 堆是用于存储Java 对象的内存区域,堆的大小在JVM 启动时就一次向操作系统
申请完成,通过 -Xmx 和 -Xms 两个选项来控制大小,Xmx 表示堆的最大大小,Xms 表示
初始大小。一旦分配完成,堆的大小就将固定,不能在内存不够时再向操作系统重新申请,
同时当内存空闲时也不能将多余的空间交还给操作系统。
在 Java 堆中内存空间的管理由JVM 来控制,对象创建由Java 应用程序控制,但是对
象所占的空间释放由管理堆内存的垃圾收集器来完成。根据垃圾收集(GC)算法的不同,
内存回收的方式和时机也会不同。
线程
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 。
ByteBuffer.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 运行时的本机内存占用。
相关推荐
在Java中调用COM组件,可以利用Java的JNI(Java Native Interface)或者第三方库如JACOB(Java Advanced COM Bridge)来实现。 **一、JACOB库的介绍** JACOB是一个Java库,它允许Java程序直接调用COM组件,无需通过...
在Java中使用VC++组件,主要是通过Java本地接口(Java Native Interface,JNI)来实现的。JNI允许Java代码调用本地(操作系统特定)代码,如C++编写的库或者DLL,以此来利用Java无法直接访问的系统功能。在这个场景...
值得注意的是,JCOM库的使用可能会受到Java版本和操作系统版本的影响,因此在实际应用中需要确保兼容性。同时,由于跨语言交互的复杂性,调试过程中可能需要对COM组件的日志和Java的异常堆栈信息进行分析。 总之,...
这种方式不将整个文件加载到内存中,而是边读边写,降低了内存消耗,提高了性能。 5. **断点续传**:为了处理网络中断或其他错误,组件可能实现了断点续传功能。这意味着用户可以在上传或下载过程中暂停,然后在...
在Java世界中,这些基本组件主要包括JVM(Java虚拟机)、类库、API(应用程序接口)以及开发工具等。下面我们将详细探讨这些组件以及它们在实际开发中的应用。 1. JVM(Java Virtual Machine) JVM是Java平台的...
在实际开发中,Java通过JACOB操作COM组件时,还需要考虑错误处理、线程安全、内存管理等问题。同时,当多个线程同时访问COM组件时,可能需要手动同步以避免竞态条件。 总结起来,Java操作COM组件是跨平台开发中的一...
Java的分页组件是Java开发中的重要工具,主要用于处理大数据量的展示问题,避免一次性加载所有数据导致内存压力过大和用户界面响应缓慢。在Web应用中,尤其在数据查询、报表展示等场景,分页是必不可少的功能。Java...
要在Java项目中使用JACOB,你需要进行以下步骤: 1. **添加依赖**:首先,将`jacob.jar`添加到项目的类路径中。如果是Maven项目,可以在pom.xml文件中添加对应的依赖。对于本地开发,确保`jacob.dll`位于系统PATH...
4. **临时文件存储**:上传的大文件不能直接存放在内存中,通常会先保存在服务器的临时目录。开发者需要确保文件的安全性,避免未授权访问,并在处理完成后及时清理临时文件。 5. **文件验证与处理**:在接收文件后...
在这个组件中,我们可以发现一系列增强的功能和优化,旨在提高Java应用程序在处理数据库任务时的性能和便利性。 首先,让我们深入理解Java中的数据库操作。Java标准版(Java SE)提供了Java Database Connectivity ...
Java的Apache POI组件是用于处理Microsoft Office格式文件的一个强大工具,特别在数据导入和导出方面表现出色。POI项目始于2001年,旨在提供一个纯Java的解决方案来读取、写入和修改Microsoft Office文档,包括Excel...
3. **Java集成**:H2数据库很容易在Java项目中集成,只需要添加相应的JAR文件到类路径中,然后通过Java代码即可创建和操作数据库。H2提供了简单的API和JDBC驱动,使得开发人员可以方便地进行数据操作。 4. **数据...
《Java组件设计源码》是一本深入探讨Java组件设计的书籍,其提供的源码是学习和理解组件设计精髓的重要资源。这本书着重于如何构建高效、可重用且具有良好架构的Java组件,对于开发者来说,无论是初级还是高级,都能...
9. **实战应用**:可能包括如何在实际项目中集成这些组件,例如在Web服务、报表系统或文档管理系统中使用PDF生成功能。 通过学习这一章的内容,开发者能够熟练掌握Java环境下处理PDF文件的技巧,提高工作效率,并且...
- **UI组件未释放**:在界面切换频繁的应用中,未释放的UI组件可能会导致内存泄漏。 ##### 4.3 JBoss底层内存泄漏 - **线程池管理**:在使用JBOSS等容器时,如果线程池配置不当,可能导致线程池中对象无法被垃圾...
当对象不再被引用时,GC会自动将其从内存中移除,释放其占用的空间。然而,这种机制并非万无一失。 ##### 2.1 对象分配与释放 在Java中,所有对象都在堆(heap)中分配内存。对象的创建通常通过`new`关键字完成,而...
2. **定义COM接口**:在Java中,你需要为C++ COM组件中的接口创建对应的Java接口。这包括声明对应的方法,使用`com.jacob.com.Dispatch`作为方法的返回类型,以及使用`com.jacob.com.Variant`作为参数类型。 3. **...
1. 堆内存:Java对象主要存储在堆内存中,过大或过多的对象可能导致堆溢出。 2. 非堆内存:包括JVM自身使用的内存(如方法区、元空间)和线程栈,这部分内存也可能导致溢出。 3. GC(Garbage Collection):Java的...
7. 存储到数据集:这里的数据集可能指的是内存中的数据结构,或者是iServer支持的特定数据格式。 8. 响应前端:将处理后的结果返回给前端应用。 整个过程展示了Java组件在GIS服务中的强大能力,以及如何通过编程...
该组件支持分块上传,对于大文件,它能够有效地将文件分割为小块,从而避免一次性加载整个文件到内存中,减少服务器内存压力。 1. **核心类与接口** - `DiskFileItemFactory`: 这是FileUpload组件中的核心工厂类,...