JVM内存详解

1 本机内存介绍

1.1 硬件限制

1.2 操作系统和虚拟内存

1.2.1 虚拟内存可增加可用内存空间, 但是可能引起性能问题

1.2.2 内核空间和用户空间

2 内存耗尽时现象

当Java 堆耗尽时,Java 应用程序很难正常运行,因为Java 应用程序必须通过分配对象来完成工作。只要Java 堆被填满,就会出现糟糕的GC 性能并抛出表示Java 堆被填满的OutOfMemoryError。

相反,一旦Java运行时开始运行并且应用程序处于稳定状态,它可以在本机堆完全耗尽之后继续正常运行。不一定会发生奇怪的行为,因为需要分配本机内存的操作比需要分配Java 堆的操作少得多。但一些常见操作还是会报错:启动线程、加载类以及执行某种类型的网络和文件I/O。

3 如何占用本机内存

3.1 java堆

Java 堆是分配了对象的内存区域。

堆的大小可以在Java 命令行使用 -Xmx 和 -Xms 选项来控制(mx 表示堆的最大大小,ms 表示初始大小)。

Java堆占用的本机内存为-Xmx,未被使用的部分为保留内存,保留内存不会分配给其他程序使用;

对于维护Java 堆的内存管理系统,需要更多本机内存来维护它的状态。例如行垃圾收集。

3.2 垃圾收集

3.3 即时(JIT)编译

JIT 编译器在运行时编译Java 字节码来优化本机可执行代码。这极大地提高了Java 运行时的速度,并且支持Java 应用程序以与本机代码相当的速度运行。

但JIT 编译器的输入(字节码)和输出(可执行代码)必须也存储在本机内存中。

3.4 类和类加载器

存储类的方式取决于具体实现。Sun JDK 使用永久生成(permanent generation,PermGen)堆区域。Java 5 的IBM 实现会为每个类加载器分配本机内存块,并将类数据存储在其中。

从最基本的层面来看,使用更多的类将需要使用更多内存。

Java运行时可以卸载类来回收空间,但是只有在非常严酷的条件下才会这样做。不能卸载单个类,而是卸载类加载器,随其加载的所有类都会被卸载。只有在以下情况下才能卸载类加载器:

Java 堆不包含对表示该类加载器的 java.lang.ClassLoader 对象的引用。

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

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

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

3.5 JNI

JNI 应用程序可能通过3 种方式增加Java 运行时的本机内存占用:

JNI 应用程序的本机代码被编译到共享库中,或编译为加载到进程地址空间中的可执行文件。大型本机应用程序可能仅仅加载就会占用大量进程地址空间。

本机代码必须与Java 运行时共享地址空间。任何本机代码分配或本机代码执行的内存映射都会耗用Java 运行时的内存。

某些JNI 函数可能在它们的常规操作中使用本机内存。GetTypeArrayElements 和GetTypeArrayRegion 函数可以将Java堆数据复制到本机内存缓冲区中,以供本机代码使用。是否复制数据依赖于运行时实现。(IBM Developer Kit for Java 5.0 和更高版本会进行本机复制)。

通过这种方式访问大量Java 堆数据可能会使用大量本机堆

3.6 NIO

直接bytebuffer会操作本机内存;

3.7 线程

线程的堆栈空间、线程本地存储(thread-local storage)和内部数据结构会占用本机内存。

堆栈大小因Java 实现和架构的不同而不同。一些实现支持为Java 线程指定堆栈大小,其范围通常在256KB 到756KB 之间。

4 调试方法和技术

4.1 检查java堆

JavaCore文件、heapdump文件;

4.2 检查本机堆

Windows 提供的PerfMon 工具;

Linux 使用命令行工具(比如 ps、top 和 pmap)能够显示应用程序的本机内存占用情况。配合使用GCMV,进行长时间跟踪后的分析。

由于JVM 前期阶段的本机内存增长而耗尽本机内存,以及内存使用随负载增加而增加,这些都是尝试在可用空间中做太多事情的例子。在这些场景中,您的选择是:

减少本机内存使用。缩小Java 堆大小是一个好的开端。

限制本机内存使用。如果您的本机内存随负载增加而增加,可以采取某种方式限制负载或为负载分配的资源。

增加可用地址空间。这可以通过以下方式实现:调优您的操作系统(例如,在Windows 上使用/3GB 开关增加用户空间,或者在Linux 上使用庞大的内核空间),更换平台(Linux 通常拥有比Windows 更多的用户空间),或者 转移到64 位操作系统。

4.3 是什么在使用本机内存

根据您的Java 设置,将会使用多少本机内存。根据以下指南粗略估算一下:

Java 堆占用的内存至少为-Xmx 值。

每个Java 线程需要堆栈空间。堆栈空间因实现不同而异,但是如果使用默认设置,每个线程至多会占用756KB 本机内存。

直接 ByteBuffer 至少会占用提供给allocate() 例程的内存值。

UMDH 支持就地 调试Windows 上本机内存泄漏,在Linux 上,您可能需要进行一些传统的调试,而不是依赖工具来解决问题。下面是一些建议的调试步骤:

提取测试案例。生成一个独立环境,您需要能够在该环境中再现本机内存泄漏。这将使调试更加简单。

尽可能缩小测试案例。尝试禁用函数来确定是哪些代码路径导致了本机内存泄漏。如果您拥有自己的JNI 库,可以尝试一次禁用一个来确定是哪个库导致了内存泄漏。

缩小Java 堆大小。Java 堆可能是进程的虚拟地址空间的最大使用者。通过减小Java 堆,可以将更多空间提供给本机内存的其他使用者。

关联本机进程大小。一旦您获得了本机内存随时间的使用情况,可以将其与应用程序工作负载和GC 数据比较。如果泄漏程度与负载级别成正比,则意味着泄漏是由每个事务或操作路径上的某个实体引起的。如果当进行垃圾收集时,本机进程大小显著减小,这意味着您没遇到内存泄漏,您拥有的是具有本机支持的对象组合(比如直接 ByteBuffer)。通过缩小Java 堆大小(从而迫使垃圾收集更频繁地发生),或者在一个对象缓存中管理对象(而不是依赖于垃圾收集器来清理对象),您可以减少本机支持对象持有的内存量。

5 消除限制

更改为64位,但是64位可能引入对象膨胀的问题;

必须关注物理内存是否满足Java程序使用,一旦物理内存不足,发生频繁的与虚拟内存交换,会严重影响性能。

JVM内存详解-阅读笔记的更多相关文章

  1. Java中堆内存和栈内存详解2

    Java中堆内存和栈内存详解   Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...

  2. NGINX高性能Web服务器详解(读书笔记)

    原文地址:NGINX高性能Web服务器详解(读书笔记) 作者:夏寥寥 第4章  Nginx服务器的高级配置 4.1 针对IPv4的内核7个参数的配置优化 说明:我们可以将这些内核参数的值追加到Linu ...

  3. 孙鑫视频VC++深入详解学习笔记

    孙鑫视频VC++深入详解学习笔记 VC++深入详解学习笔记 Lesson1: Windows程序运行原理及程序编写流程 Lesson2: 掌握C++基本语法 Lesson3: MFC框架程序剖析 Le ...

  4. DDR3内存详解,存储器结构+时序+初始化过程

    DDR3内存详解,存储器结构+时序+初始化过程 标签: DDR3存储器博客 2017-06-17 16:10 1943人阅读 评论(1) 收藏 举报  分类: 硬件开发基础(2)  转自:http:/ ...

  5. NAND_FLASH_内存详解与读写寻址方式

    一.内存详解 NAND闪存阵列分为一系列128kB的区块(block),这些区块是 NAND器件中最小的可擦除实体.擦除一个区块就是把所有的位(bit)设置为"1"(而所有字节(b ...

  6. JVM结构详解

    JVM 结构详解 JVM 结构图 程序计数器(PC 寄存器) 程序计数器的定义 程序计数器是一块较小的内存空间,是当前线程正在执行的那条字节码指令的地址.若当前线程正在执行的是一个本地方法,那么此时程 ...

  7. TCP/IP详解学习笔记

    TCP/IP详解学习笔记(1)-基本概念 TCP/IP详解学习笔记(2)-数据链路层 TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议 TCP/IP详解学习笔记(4)-ICMP协议, ...

  8. [转]JVM指令详解(上)

    作者:禅楼望月(http://www.cnblogs.com/yaoyinglong) 本文主要记录一些JVM指令,便于记忆与查阅. 一.未归类系列A 此系列暂未归类. 指令码    助记符      ...

  9. TCP/IP详解学习笔记 这位仁兄写得太好了

      TCP/IP详解学习笔记(1)-基本概念 为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣 ...

随机推荐

  1. 【Android应用开发】 推送原理解析 极光推送使用详解 (零基础精通推送)

    作者 : octopus_truth 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/45046283 推送技术产生场景 : -- ...

  2. Java正则表达式小记

    http://blog.csdn.net/pipisorry/article/details/51059500 正则表达式的一般规则都一样,见[python正则表达式] java正则表达式中的特殊字符 ...

  3. python访问redis

    python访问redis 1 Linux上安装redis a) 下载 $ wget http://download.redis.io/releases/redis-3.0.5.tar.gz b) 编 ...

  4. A*寻路算法入门(三)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  5. android 标准OTA升级流程

    标准的OTA升级流程包括一下几个步骤: 1.Android设备首先会与OTA服务器进行交互,如果有更新会推送给客户.推送的信息常常会包含OTA更新包的下载地址和一些版本信息. 2.Update程序会将 ...

  6. LOV里的值直接引用系统里定义的值集的值,且具有值集的安全性控制

    fnd_flex_server.check_value_security(p_security_check_mode => 'YH', p_flex_value_set_id => p_f ...

  7. javascript 把时间戳转为时间 ajax HTML拼装

    这个目的是记下来,好让我以后可以看一下,这个脚本可是反反复复写了我N天啊!! 全部写下,以备后用! Date.prototype.format = function(format) { var o = ...

  8. (二)php的常量和变量

    [php在命令行下接收参数] 如果在命令行调试php,传入的参数通过$argv获取,注意其中包含了文件名这一个元素,数组中元素的个数通过$argc获取. [可变变量] 指的是变量的名称可变,变量的标识 ...

  9. [leetcode]经典算法题- String to Integer (atoi)

    题目描述: 把字符串转化为整数值 原文描述: Implement atoi to convert a string to an integer. Hint: Carefully consider al ...

  10. (十五)UITableViewCell的常见属性

    UItableViewCellStyle: typedef NS_ENUM(NSInteger, UITableViewCellStyle) { UITableViewCellStyleDefault ...