1. 程式人生 > >JVM記憶體調優相關的一些筆記(雜)

JVM記憶體調優相關的一些筆記(雜)

Max memory = [-Xmx] + [-XX:MaxPermSize] + number_of_threads * [-Xss]

MaxPerm/MetaSize + MaxDirectMemorySize + Xmx(執行緒棧一般只有幾十M,可以忽略)這差不多就是JVM可以佔用的最大記憶體了

整個Java程序分為heap和non-heap兩部分,每部分有以下幾個概念:

init represents the initial amount of memory (in bytes) that the Java virtual machine requests from the operating system for memory management during startup. The Java virtual machine may request additional memory from the operating system and may also release memory to the system over time. The value of init may be undefined.
used represents the amount of memory currently used (in bytes).
committed represents the amount of memory (in bytes) that is guaranteed to be available for use by the Java virtual machine. The amount of committed memory may change over time (increase or decrease). The Java virtual machine may release memory to the system and committed could be less than init. committed will always be greater than or equal to used.
max represents the maximum amount of memory (in bytes) that can be used for memory management. Its value may be undefined. The maximum amount of memory may change over time if defined. The amount of used and committed memory will always be less than or equal to max if max is defined. A memory allocation may fail if it attempts to increase the used memory such that used > committed even if used <= max would still be true (for example, when the system is low on virtual memory).

reserved memory 是指JVM 通過mmaped PROT_NONE 申請的虛擬地址空間,在頁表中已經存在了記錄(entries),保證了其他程序不會被佔用,會page faults,committed memory 是JVM向操做系統實際分配的記憶體(malloc/mmap),mmaped PROT_READ | PROT_WRITE,仍然會page faults 但是跟 reserved 不同,完全核心處理像什麼也沒發生一樣。used memory 是JVM實際儲存了資料(Java物件)的大小,當used~=committed的時候,heap就會grow up,-Xmx設定了上限。

關於committed,reserved以及rss之間的關係實際情況要複雜的多:

  • reserved 但是沒有 committed pages 不算 rss.
  • page out 的算committed,但是不算 rss.
  • 已經 committed 的也不一定在rss內(committed > rss): malloc/mmap is lazy unless told otherwise. Pages are only backed by physical memory once they're accessed.

committed 可能會比init小,因為JVM可能會將記憶體還給OS,但是一定不會小於used,也就是commited是操做系統保證JVM可以使用的記憶體空間,但是不一定都使用了。init是啟動時後JVM向OS申請的記憶體,max是能夠使用的最大邊界值。注意這裡說的都是虛擬記憶體,所以理論上整個操做系統commited的記憶體為實體記憶體加上交換空間的大小,換句話說如果commited超過實體記憶體的話,多餘的部分就會被換出到磁碟。

JVM(堆)佔用的實體記憶體是跟committed相關,committed變小意味著JVM將記憶體還給OS了,則同過top命令看到的RSS會變小。

測試發現:committed後的記憶體是不會還給OS的,FullGC後used(堆記憶體)降下來了,但是隻要committed不變,佔用的RSS就不會降下來。目前用的CMS也沒有強制將記憶體還給OS的方法。Java堆佔用的實體記憶體不會超過-Xmx,但是一個程序具體佔用多少實體記憶體不等於used,也不等於commited,目前來說JVM如何向OS申請記憶體和如何將記憶體還給OS我們是不知道的。

top命令檢視到的RSS大於-Xmx設定的值,超過的部分肯定是堆外記憶體,如果大很多那說明對外記憶體使用的是有問題的。

OS

commit charge:

In thinking about virtual memory, there are two concepts that every programmer should understand: resident set size and commit charge. The second is easiest to explain: it's the total amount of memory that your program might be able to modify (ie, it excludes read-only memory-mapped files and program code). The potential commit charge for an entire system is the sum of RAM and swap space, and no program can exceed this. It doesn't matter how big your virtual address space is: if you have 2G of RAM, and 2G of swap, you can never work with more than 4G of in-memory data; there's no place to store it.

dirty page:

One final concept: pages in the resident set can be “dirty,” meaning that the program has changed their content. A dirty page must be written to swap space before its physical memory can be used by another page. By comparison, a clean (unmodified) page may simply be discarded; it will be reloaded from disk when needed. If you can guarantee that a page will never be modified, it doesn't count against a program's commit charge — we'll return to this topic when discussing memory-mapped files.

Below is a picture showing an example of a memory pool:

    +----------------------------------------------+
    +////////////////           |                  +
    +////////////////           |                  +
    +----------------------------------------------+

    |--------|
       init
    |---------------|
           used
    |---------------------------|
              committed
    |----------------------------------------------|

通過jconsole的MBean可以很方便的監控heap,noheap以及commited,used這些內容:

jconsole.png

JVM非堆的記憶體可能會有哪些?GC,JIT,Threads,Classes and Classloaders(PermGen),NIO(direct buffer)

But besides the memory consumed by your application, the JVM itself also needs some elbow room. The need for it derives from several different reasons:

  • Garbage collection. As you might recall, Java is a garbage-collected language. In order for the garbage collector to know which objects are eligible for collection, it needs to keep track of the object graphs. So this is one part of the memory lost to this internal bookkeeping. G1 is especially known for its excessive appetite for additional memory, so be aware of this.

  • JIT optimization. Java Virtual Machine optimizes the code during runtime. Again, to know which parts to optimize it needs to keep track of the execution of certain code parts. So again, you are going to lose memory.

  • Off-heap allocations. If you happen to use off-heap memory, for example while using direct or mapped ByteBuffers yourself or via some clever 3rd party API then voila – you are extending your heap to something you actually cannot control via JVM configuration.

  • JNI code. When you are using native code, for example in the format of Type 2database drivers, then again you are loading code in the native memory.

  • Metaspace. If you are an early adopter of Java 8, you are using metaspace instead of the good old permgen to store class declarations. This is unlimited and in a native part of the JVM.

虛擬記憶體不重要,尤其是在64位作業系統上,重要的是RSS,但是有時它也不一定就說明你的程式實際需要使用的記憶體。JVM佔用的實體記憶體超過-Xmx設定的值?

But RSS is also misleading, especially on a lightly loaded machine. The operating system doesn't expend a lot of effort to reclaiming the pages used be a process. There's little benefit to be gained by doing so, and the potential for an expensive page fault if the process touches the page in the future. As a result, the RSS statistic may include lots of pages that aren't in active use.

限制程序能夠使用的實體記憶體:貌似不是很容易,主要原因是程序fork子程序

  • http://unix.stackexchange.com/questions/44985/limit-memory-usage-for-a-single-linux-process

  • http://coldattic.info/shvedsky/pro/blogs/a-foo-walks-into-a-bar/posts/40

DirectByteBuffer

Examining a heap dump for java.nio.DirectByteBuffer instances should provide further insight.

direct-bytebuffer.png

-XX:MaxDirectMemorySize 可以限制JVM使用DirectMemory的大小。

jconsole non-heap memory:

Non-heap memory includes a method area shared among all threads and memory required for the internal processing or optimization for the Java VM. It stores per-class structures such as a runtime constant pool, field and method data, and the code for methods and constructors. The method area is logically part of the heap but, depending on the implementation, a Java VM may not garbage collect or compact it. Like the heap memory, the method area may be of a fixed or variable size. The memory for the method area does not need to be contiguous.

jconsole中看到的NonHeapMemory不包括direct buffer和mapped,可以通過java.nio中MBean監控,實體記憶體在linux下用top檢視,在windows下工作管理員看到有些問題

jconsole-direct-and-map.png

通過pmap能檢視到mapped的檔案:pamp -x :

pmap.png

pmap2.png

MappedByteBuffer和DirectByteBuffer雖然是堆外的記憶體但是通過FullGC是可以“回收”的。

Garbage Collection of Direct/Mapped Buffers

That brings up another topic: how does the non-heap memory for direct buffers and mapped files get released? After all, there's no method to explicitly close or release them. The answer is that they get garbage collected like any other object, but with one twist: if you don't have enough virtual memory space or commit charge to allocate a direct buffer, that will trigger a full collection even if there's plenty of heap memory available. Normally, this won't be an issue: you probably won't be allocating and releasing direct buffers more often than heap-resident objects. If, however, you see full GC's appearing when you don't think they should, take a look at your program's use of buffers.

使用Direct buffer的場景:

In fact, the only reason that I can see for using direct buffers in a pure Java program is that they won't be moved during garbage collection. If you've read my article on reference objects, you'll remember that the garbage collector compacts the heap after disposing of dead objects. If you have large blocks of heap memory allocated as buffers, they may get moved as part of compaction, and no matter how fast your CPU, that takes time; it's not something you want to do on every full collection. Since the direct buffer lives outside of the heap, it isn't affected by collections. On the other hand, every data access is a JNI call. Only benchmarking will tell you whether this helps or hurts your particular application.

What's using my native memory?

Once you have determined you are running out of native memory, the next logical question is: What's using that memory? Answering this question is hard because, by default, Windows and Linux do not store information about which code path is allocated a particular chunk of memory.

如何監控和排查non-heap 或 native memory leak

  • IBM Support Assistant: https://www-01.ibm.com/marketing/iwm/iwm/web/reg/download.do?source=isa&S_PKG=isa5&lang=en_US&cp=UTF-8&dlmethod=http
  • Preprocessor level: Dmalloc
  • Linker level: Ccmalloc
  • Runtime-linker level: NJAMD
  • Emulator-based: memcheck
  • JNI leaking: Valgrind memcheck http://www.oracle.com/technetwork/java/javase/memleaks-137499.html#gbyvk
  • Java core file: http://www.javacodegeeks.com/2013/02/analysing-a-java-core-dump.html
  • NMT Native Memory Tracking: https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html 注意目前(7u40)NMT只能用來分析HotSpot internal memory usage,不能分析第三方的JNI.
  • GCMV: https://www.ibm.com/developerworks/java/jdk/tools/gcmv/ https://www.ibm.com/developerworks/community/blogs/troubleshootingjava/entry/gcmv_native_memory?lang=en

相比分析堆記憶體的洩漏,分析non-heap的要困難的多,不同的場景需要不同的工具去分析。

一些連結:

http://www.ibm.com/developerworks/linux/library/j-nativememory-linux/

http://docs.oracle.com/javase/7/docs/api/java/lang/management/MemoryUsage.html

http://stackoverflow.com/questions/561245/virtual-memory-usage-from-java-under-linux-too-much-memory-used

http://stackoverflow.com/questions/1612939/why-does-the-sun-jvm-continue-to-consume-ever-more-rss-memory-even-when-the-heap

(下面這兩個答案很有用)

https://plumbr.eu/blog/memory-leaks/why-does-my-java-process-consume-more-memory-than-xmx

http://www.importnew.com/14292.htm

相關推薦

JVM記憶體調相關一些筆記

Max memory = [-Xmx] + [-XX:MaxPermSize] + number_of_threads * [-Xss] MaxPerm/MetaSize + MaxDirectMemorySize + Xmx(執行緒棧一般只有幾十M,可以忽略)這差不多就是JVM可以佔用的最大記憶體了 整個

ETL調一些分享轉載

ant 想法 one gin targe 收集 commit 是否 可見 如在上篇文章《ETL調優的一些分享(上)》中已介紹的,ETL是構建數據倉庫的必經一環,它的執行性能對於數據倉庫構建性能有重要意義,因此對它進行有效的調優將十分重要。ETL業務的調優可以從若幹思路開展,

ETL調一些分享轉載

經歷 信息 同時 讀取 ges 解決辦法 排除 硬件配置 times ETL是構建數據倉庫的重要一環。通過該過程用戶將所需數據提取出來,並按照已定義的模型導入數據倉庫。由於ETL是建立數據倉庫的必經過程,它的效率將影響整個數據倉庫的構建,因此它的有效調優具有很高的重要性。在

Java效能優化系列二jvm記憶體調

首先需要注意的是在對JVM記憶體調優的時候不能只看作業系統級別Java程序所佔用的記憶體,這個數值不能準確的反應堆記憶體的真實佔用情況,因為GC過後這個值是不會變化的,因此記憶體調優的時候要更多地使用JDK提供的記憶體檢視工具,比如JConsole和Java VisualVM(jvisua

[jvm]五tomcat效能調和效能監控visualvm

1、JDK記憶體優化 根據伺服器物理內容情況配置相關引數優化tomcat效能。當應用程式需要的記憶體超出堆的最大值時虛擬機器就會提示記憶體溢位,並且導致應用服務崩潰。因此一般建議堆的最大值設定為可用記憶體的最大值的80%。 Tomcat預設可以使用的記憶體為128MB,在較大型的應用專案中,

JVM記憶體調 - 淺析 20181121

一.引言 JVM在整個jdk中處於最底層,負責於作業系統的互動,用來遮蔽作業系統環境,提供一個完整的Java執行環境,因此也叫虛擬計算機。作業系統執行JVM是通過jdk中Java.exe來完成的。 每個使用Java的開發者都知道Java位元組碼是在JRE中執行(JRE: J

jvm記憶體調處理機制

1.棧和堆 棧是執行時的單位,解決程式如何執行,代表處理邏輯 堆是儲存單位,解決資料儲存問題,代表資料 2. 分配記憶體按照8的整數倍 物件的引用: 強引用(宣告物件時虛擬機器生成的引用,不會被回收), 軟引用(快取,剩餘記憶體不足時被回收) 弱引用(一定被回收) 4.垃圾回

jvm記憶體調工具

jvm記憶體調優工具 1、jps 2、jstat 3、jinfo 4、jmap 5、jstack 參考文獻 1、jps 全名:Java Virtual Machine Process Status Tool 與linu

TOMCAT連線調JVM記憶體調

開啟tomcat的server.xml檔案,要調整Tomcat的預設最大連線數,可以增加這兩個屬性的值,並且使acceptCount大於等於maxThreads, <Connector port="8080" redirectPort="8443"   connect

jvm系列四:jvm記憶體調

JVM引數的含義 例項見例項分析 引數名稱 含義 預設值 -Xms 初始堆大小 實體記憶體的1/64(<1GB) 預設(MinHeapFreeRatio引數可以調整)空餘堆記憶體小於40%時,JVM就會增大堆直到-Xmx的最大限制. -Xmx 最大堆大小 實體記憶體的1/4(&

jvm系列(五):tomcat效能調和效能監控visualvm

tomcat伺服器優化 1、JDK記憶體優化    根據伺服器物理內容情況配置相關引數優化tomcat效能。當應用程式需要的記憶體超出堆的最大值時虛擬機器就會提示記憶體溢位,並且導致應用服務崩潰。因此一般建議堆的最大值設定為可用記憶體的最大值的80%。 Tomcat預設可以使用的記憶體為128MB,在較大

Spark官方調文檔翻譯轉載

區域 ng- 完整 好的 java類型 int 單個 rdd 常見 Spark調優 由於大部分Spark計算都是在內存中完成的,所以Spark程序的瓶頸可能由集群中任意一種資源導致,如:CPU、網絡帶寬、或者內存等。最常見的情況是,數據能裝進內存,而瓶頸是網絡帶寬;當

java面向物件學習相關簡要筆記2

繼承: 類的繼承,指在一個現有的類的基礎上去構建一個新的類,構建出來的新類被稱為子類,現有的類被稱為父類,子類會擁有父類所有可繼承的屬性和方法。 class Animal{ String name; void shout(){ System.out

java面向物件學習相關簡要筆記3

抽象類: 具體例項: abstract void shout(); //定義抽象方法shout() abstract class Animal //定義抽象類 Animal {

調度框架學習筆記3—— 集群調度框架的架構演進過程

用戶服 工程師 github 應用層 ext 相對 實習 poll 多維 本章是 The evolution of cluster scheduler architectures 文章的學習筆記。這篇文章討論了這些年調度架構是如何發展的以及為什麽會這樣發展。 首先介紹一下這

Spark官方調文件翻譯轉載

Spark調優 由於大部分Spark計算都是在記憶體中完成的,所以Spark程式的瓶頸可能由叢集中任意一種資源導致,如:CPU、網路頻寬、或者記憶體等。最常見的情況是,資料能裝進記憶體,而瓶頸是網路頻寬;當然,有時候我們也需要做一些優化調整來減少記憶體佔用,例如將RDD以序列化格式儲存(storing RD

關於ARP欺騙與MITM中間人攻擊一些筆記

測試環境如下: 拓撲圖: 閘道器: ASUS RT-N10+(DD-WRT) IP:192.168.1.1/24 攻擊主機: BackTrack 5R3 IP:192.168.1.104/24 被攻擊主機(1): windows 7 IP:

關於servlet+jsp+java實現Web登陸頁介面的一些筆記

2.3.1響應訊息格式HTTP響應訊息的格式如下所示:狀態行通用資訊頭|響應頭|實體頭CRLF實體內容其中:狀態行 = 版本號 [空格] 狀態碼 [空格] 原因 [回車換行]狀態行舉例:Eg1:HTTP/1.0 200 OK Eg2:HTTP/1.1 400 Bad RequestHTTP響應訊息例項如下所示

unity指令碼的一些筆記

Transform 場景變換 一、座標系 1. 變數 a. Right、Up和Forward 分別表示表示物體本身座標系(local space)的x,y和z方向向量 2. 函式 a. TransformPoint() 把

SQL Server 效能調2 之索引Index的建立

前言 索引是關係資料庫中最重要的物件之一,他能顯著減少磁碟I/O及邏輯讀取的消耗,並以此來提升 SELECT 語句的查詢效能。但它是一把雙刃劍,使用不當反而會影響效能:他需要額外的空間來存放這些索引資訊,並且當資料更新時需要一些額外開銷來保持索引的同步。 形象的來說索引就像