[{"data":1,"prerenderedAt":1181},["ShallowReactive",2],{"blog-\u002Fblog\u002Fjava-jvm-memory-heap-stack":3},{"id":4,"title":5,"body":6,"description":1167,"difficulty":1168,"extension":1169,"framework":1170,"frameworkSlug":71,"meta":1171,"navigation":737,"order":79,"path":1172,"qaPath":1173,"seo":1174,"stem":1175,"subtopic":1176,"topic":1177,"topicSlug":1178,"updated":1179,"__hash__":1180},"blog\u002Fblog\u002Fjava-jvm-memory-heap-stack.md","Java JVM Memory Explained — Heap, Stack, and Everything In Between",{"type":7,"value":8,"toc":1150},"minimark",[9,14,27,31,43,53,66,160,171,175,178,204,211,215,224,280,289,293,304,312,341,352,356,371,378,395,406,410,417,473,484,498,502,509,523,590,597,601,611,614,625,629,636,639,653,663,696,699,703,710,764,783,787,790,849,938,943,947,954,1011,1029,1033,1112,1116,1146],[10,11,13],"h2",{"id":12},"why-jvm-memory-matters-in-interviews","Why JVM memory matters in interviews",[15,16,17,18,22,23,26],"p",{},"Questions about JVM memory come up in almost every Java backend interview. The reason is\nsimple: memory bugs — leaks, OOM errors, GC pauses — are some of the hardest problems to\ndiagnose in production, and interviewers want to see that you have a mental model of ",[19,20,21],"em",{},"where","\ndata lives and ",[19,24,25],{},"when"," it gets cleaned up. This article builds that model from the ground up.",[10,28,30],{"id":29},"the-two-main-regions-stack-and-heap","The two main regions: stack and heap",[15,32,33,34,38,39,42],{},"The JVM divides runtime memory into two primary areas visible to application code: the\n",[35,36,37],"strong",{},"stack"," and the ",[35,40,41],{},"heap",".",[15,44,45,46,48,49,52],{},"The ",[35,47,37],{}," is a per-thread, LIFO structure. Every method call pushes a ",[35,50,51],{},"stack frame","\ncontaining the method's local variables, parameters, and a work area (operand stack) for\nexecuting bytecode. When the method returns, the frame is popped and everything in it\ndisappears immediately — no GC needed.",[15,54,45,55,57,58,62,63,42],{},[35,56,41],{}," is a single region shared by all threads. Every object created with ",[59,60,61],"code",{},"new"," lands\nhere, including arrays. The heap is managed by the ",[35,64,65],{},"garbage collector",[67,68,73],"pre",{"className":69,"code":70,"language":71,"meta":72,"style":72},"language-java shiki shiki-themes github-light github-dark","void demo() {\n    int x = 42;                  \u002F\u002F x lives on the stack (primitive local)\n    String s = new String(\"hi\"); \u002F\u002F the String object lives on the heap;\n                                 \u002F\u002F s (the reference variable) lives on the stack\n}\n\u002F\u002F When demo() returns, x and s are gone; the String may be GC'd\n","java","",[59,74,75,92,115,142,148,154],{"__ignoreMap":72},[76,77,80,84,88],"span",{"class":78,"line":79},"line",1,[76,81,83],{"class":82},"szBVR","void",[76,85,87],{"class":86},"sScJk"," demo",[76,89,91],{"class":90},"sVt8B","() {\n",[76,93,95,98,101,104,108,111],{"class":78,"line":94},2,[76,96,97],{"class":82},"    int",[76,99,100],{"class":90}," x ",[76,102,103],{"class":82},"=",[76,105,107],{"class":106},"sj4cs"," 42",[76,109,110],{"class":90},";                  ",[76,112,114],{"class":113},"sJ8bj","\u002F\u002F x lives on the stack (primitive local)\n",[76,116,118,121,123,126,129,132,136,139],{"class":78,"line":117},3,[76,119,120],{"class":90},"    String s ",[76,122,103],{"class":82},[76,124,125],{"class":82}," new",[76,127,128],{"class":86}," String",[76,130,131],{"class":90},"(",[76,133,135],{"class":134},"sZZnC","\"hi\"",[76,137,138],{"class":90},"); ",[76,140,141],{"class":113},"\u002F\u002F the String object lives on the heap;\n",[76,143,145],{"class":78,"line":144},4,[76,146,147],{"class":113},"                                 \u002F\u002F s (the reference variable) lives on the stack\n",[76,149,151],{"class":78,"line":150},5,[76,152,153],{"class":90},"}\n",[76,155,157],{"class":78,"line":156},6,[76,158,159],{"class":113},"\u002F\u002F When demo() returns, x and s are gone; the String may be GC'd\n",[15,161,162,163,166,167,170],{},"The key insight: ",[35,164,165],{},"the reference variable and the object it points to are in different\nplaces",". The reference (an address-sized slot) lives wherever the variable was declared —\non the stack if it's a local variable, or inside another heap object if it's a field. The\n",[19,168,169],{},"object"," always lives on the heap.",[10,172,174],{"id":173},"stack-frames-in-detail","Stack frames in detail",[15,176,177],{},"Each stack frame holds three things:",[179,180,181,188,198],"ol",{},[182,183,184,187],"li",{},[35,185,186],{},"Local variable array"," — the method's parameters and declared local variables.\nPrimitives are stored by value; object references are stored as pointers.",[182,189,190,193,194,197],{},[35,191,192],{},"Operand stack"," — a push\u002Fpop work area the JVM uses to execute individual bytecodes\n(e.g., it pushes two ints, executes ",[59,195,196],{},"iadd",", and the result is on top).",[182,199,200,203],{},[35,201,202],{},"Frame data"," — a reference to the current class's runtime constant pool and the\nreturn address so the JVM knows where to jump when this method returns.",[15,205,206,207,210],{},"Because each thread has its own stack, local variables are ",[35,208,209],{},"inherently thread-safe"," —\nno other thread can see or modify them. Synchronization is only needed for shared heap data.",[10,212,214],{"id":213},"stackoverflowerror","StackOverflowError",[15,216,217,218,221,222,42],{},"The stack has a fixed size, set by ",[59,219,220],{},"-Xss"," (default ~512 KB–1 MB depending on the JVM and\nOS). Deep recursion without a base case exhausts this space and triggers a\n",[59,223,214],{},[67,225,227],{"className":69,"code":226,"language":71,"meta":72,"style":72},"int factorial(int n) {\n    return n * factorial(n - 1); \u002F\u002F no base case → infinite recursion\n}\n\u002F\u002F java.lang.StackOverflowError\n",[59,228,229,244,271,275],{"__ignoreMap":72},[76,230,231,234,237,239,241],{"class":78,"line":79},[76,232,233],{"class":82},"int",[76,235,236],{"class":86}," factorial",[76,238,131],{"class":90},[76,240,233],{"class":82},[76,242,243],{"class":90}," n) {\n",[76,245,246,249,252,255,257,260,263,266,268],{"class":78,"line":94},[76,247,248],{"class":82},"    return",[76,250,251],{"class":90}," n ",[76,253,254],{"class":82},"*",[76,256,236],{"class":86},[76,258,259],{"class":90},"(n ",[76,261,262],{"class":82},"-",[76,264,265],{"class":106}," 1",[76,267,138],{"class":90},[76,269,270],{"class":113},"\u002F\u002F no base case → infinite recursion\n",[76,272,273],{"class":78,"line":117},[76,274,153],{"class":90},[76,276,277],{"class":78,"line":144},[76,278,279],{"class":113},"\u002F\u002F java.lang.StackOverflowError\n",[15,281,282,283,285,286,288],{},"The fix is almost always a missing or incorrect base case, not a larger ",[59,284,220],{},". Reserve\n",[59,287,220],{}," tuning for genuinely deep but bounded recursion (e.g., recursive descent parsers on\nlarge documents).",[10,290,292],{"id":291},"the-generational-heap","The generational heap",[15,294,295,296,299,300,303],{},"HotSpot organises the heap into ",[35,297,298],{},"generations"," based on the ",[35,301,302],{},"weak generational\nhypothesis",": most objects die young. Collecting only the short-lived objects most of the\ntime keeps GC pauses short.",[67,305,310],{"className":306,"code":308,"language":309},[307],"language-text","┌─────────────────────────────────────────────────────┐\n│                     Java Heap                       │\n│  ┌──────────────────────────┐  ┌──────────────────┐ │\n│  │     Young Generation     │  │   Old Generation  │ │\n│  │  ┌────────┬──┬──────┐   │  │   (Tenured)       │ │\n│  │  │ Eden   │S0│  S1  │   │  │                   │ │\n│  │  └────────┴──┴──────┘   │  │                   │ │\n│  └──────────────────────────┘  └──────────────────┘ │\n└─────────────────────────────────────────────────────┘\n","text",[59,311,308],{"__ignoreMap":72},[313,314,315,321,327],"ul",{},[182,316,317,320],{},[35,318,319],{},"Eden"," — new objects are allocated here. It fills quickly.",[182,322,323,326],{},[35,324,325],{},"Survivor 0 \u002F S1"," — objects that survived at least one Minor GC are copied here\nalternately, tracking their age in bits of the mark word.",[182,328,329,332,333,336,337,340],{},[35,330,331],{},"Old Gen (Tenured)"," — objects that reach a configurable age threshold\n(",[59,334,335],{},"-XX:MaxTenuringThreshold",", default 15) are ",[35,338,339],{},"promoted"," here.",[15,342,343,344,347,348,351],{},"A ",[35,345,346],{},"Minor GC"," collects Young Gen only — fast, frequent, short pause. A ",[35,349,350],{},"Full GC","\ncollects the entire heap and triggers when Old Gen fills up; it is slow and its pause can\naffect latency SLAs.",[10,353,355],{"id":354},"metaspace-replacing-permgen","Metaspace (replacing PermGen)",[15,357,358,359,362,363,366,367,370],{},"Java 8 removed ",[35,360,361],{},"PermGen"," and replaced it with ",[35,364,365],{},"Metaspace",", which lives in ",[19,368,369],{},"native\nmemory"," outside the Java heap. Metaspace stores class metadata — bytecode, method\ndescriptors, constant pools — for every loaded class.",[15,372,373,374,377],{},"Because Metaspace is in native memory it grows dynamically. Without a cap it can exhaust\nthe OS's virtual address space, so set ",[59,375,376],{},"-XX:MaxMetaspaceSize"," on servers where the class\ncount is bounded.",[67,379,383],{"className":380,"code":381,"language":382,"meta":72,"style":72},"language-bash shiki shiki-themes github-light github-dark","java -XX:MaxMetaspaceSize=256m MyServer\n","bash",[59,384,385],{"__ignoreMap":72},[76,386,387,389,392],{"class":78,"line":79},[76,388,71],{"class":86},[76,390,391],{"class":106}," -XX:MaxMetaspaceSize=256m",[76,393,394],{"class":134}," MyServer\n",[15,396,397,398,401,402,405],{},"The old ",[59,399,400],{},"OutOfMemoryError: PermGen space"," is gone; ",[59,403,404],{},"OutOfMemoryError: Metaspace"," is its\nequivalent. It usually means class loaders are leaking (common with hot-redeploy in\napplication servers).",[10,407,409],{"id":408},"object-headers-and-memory-overhead","Object headers and memory overhead",[15,411,412,413,416],{},"Every heap object carries a hidden ",[35,414,415],{},"object header"," before its fields:",[418,419,420,436],"table",{},[421,422,423],"thead",{},[424,425,426,430,433],"tr",{},[427,428,429],"th",{},"Part",[427,431,432],{},"Size (64-bit, compressed oops)",[427,434,435],{},"Purpose",[437,438,439,451,462],"tbody",{},[424,440,441,445,448],{},[442,443,444],"td",{},"Mark word",[442,446,447],{},"8 bytes",[442,449,450],{},"hashCode, GC age, lock state, biased-locking",[424,452,453,456,459],{},[442,454,455],{},"Class pointer",[442,457,458],{},"4 bytes (compressed)",[442,460,461],{},"pointer to Metaspace metadata",[424,463,464,467,470],{},[442,465,466],{},"Padding",[442,468,469],{},"0–4 bytes",[442,471,472],{},"align to 8-byte boundary",[15,474,475,476,479,480,483],{},"An ",[59,477,478],{},"Object"," with no fields still occupies ",[35,481,482],{},"16 bytes",". Knowing this helps when evaluating\nwhether using millions of small objects is viable versus using primitive arrays.",[15,485,486,489,490,493,494,497],{},[35,487,488],{},"Compressed oops"," (",[59,491,492],{},"-XX:+UseCompressedOops",", on by default when heap ≤ 32 GB) store\nreferences as 32-bit word offsets rather than 64-bit raw pointers, shrinking every\nreference field from 8 → 4 bytes. Crossing the 32 GB heap threshold disables compressed\noops and every reference grows back to 8 bytes — heap usage often ",[19,495,496],{},"increases",", not\ndecreases.",[10,499,501],{"id":500},"escape-analysis-and-stack-allocation","Escape analysis and stack allocation",[15,503,504,505,508],{},"The JIT compiler performs ",[35,506,507],{},"escape analysis"," to determine whether an object reference\nescapes the method or thread that created it. If it doesn't escape, the JVM can:",[313,510,511,517],{},[182,512,513,516],{},[35,514,515],{},"Allocate it on the stack"," — the object is freed when the frame pops, with zero GC\ninvolvement.",[182,518,519,522],{},[35,520,521],{},"Scalar-replace"," it — decompose it into individual primitive fields, eliminating the\nobject entirely.",[67,524,526],{"className":69,"code":525,"language":71,"meta":72,"style":72},"void compute() {\n    Point p = new Point(1, 2); \u002F\u002F p never escapes this method\n    int sum = p.x + p.y;       \u002F\u002F JIT may replace p with two int locals — no heap allocation\n}\n",[59,527,528,537,565,586],{"__ignoreMap":72},[76,529,530,532,535],{"class":78,"line":79},[76,531,83],{"class":82},[76,533,534],{"class":86}," compute",[76,536,91],{"class":90},[76,538,539,542,544,546,549,551,554,557,560,562],{"class":78,"line":94},[76,540,541],{"class":90},"    Point p ",[76,543,103],{"class":82},[76,545,125],{"class":82},[76,547,548],{"class":86}," Point",[76,550,131],{"class":90},[76,552,553],{"class":106},"1",[76,555,556],{"class":90},", ",[76,558,559],{"class":106},"2",[76,561,138],{"class":90},[76,563,564],{"class":113},"\u002F\u002F p never escapes this method\n",[76,566,567,569,572,574,577,580,583],{"class":78,"line":117},[76,568,97],{"class":82},[76,570,571],{"class":90}," sum ",[76,573,103],{"class":82},[76,575,576],{"class":90}," p.x ",[76,578,579],{"class":82},"+",[76,581,582],{"class":90}," p.y;       ",[76,584,585],{"class":113},"\u002F\u002F JIT may replace p with two int locals — no heap allocation\n",[76,587,588],{"class":78,"line":144},[76,589,153],{"class":90},[15,591,592,593,596],{},"Escape analysis is enabled by default (",[59,594,595],{},"-XX:+DoEscapeAnalysis","). You can't force it, but\nkeeping temporary objects local (not returning them, not storing them in fields or statics)\ngives the JIT the best chance to eliminate the allocation.",[10,598,600],{"id":599},"tlabs-why-allocation-is-cheap","TLABs — why allocation is cheap",[15,602,603,604,606,607,610],{},"Allocating on the shared Eden naively would require a thread-safe pointer bump on every\n",[59,605,61],{},". The JVM avoids this by giving each thread a ",[35,608,609],{},"Thread-Local Allocation Buffer (TLAB)","\n— a private slice of Eden. Allocation within a TLAB is just a pointer bump with no\nsynchronization.",[15,612,613],{},"When a TLAB fills, the thread requests a new one from Eden under a brief lock. Objects\nlarger than a TLAB are allocated directly in Eden or promoted straight to Old Gen\n(humongous objects in G1).",[15,615,616,617,620,621,624],{},"The result: ",[59,618,619],{},"new SomeObject()"," is nearly as cheap as ",[59,622,623],{},"malloc"," in C — the cost is paid at\nGC time, not at allocation time.",[10,626,628],{"id":627},"gc-roots-and-memory-leaks","GC roots and memory leaks",[15,630,631,632,635],{},"The garbage collector starts from ",[35,633,634],{},"GC roots"," — objects guaranteed to be live — and traces\nall reachable objects. Anything reachable from a root is kept alive; everything else is\neligible for collection.",[15,637,638],{},"GC roots include:",[313,640,641,644,647,650],{},[182,642,643],{},"Local variables in active stack frames",[182,645,646],{},"Static fields of loaded classes",[182,648,649],{},"JNI references in native code",[182,651,652],{},"Active thread objects themselves",[15,654,343,655,658,659,662],{},[35,656,657],{},"Java memory leak"," is not memory the GC can't see; it's memory the GC ",[19,660,661],{},"won't"," collect\nbecause a root still holds a reference to it (directly or through a chain).",[67,664,666],{"className":69,"code":665,"language":71,"meta":72,"style":72},"static List\u003CObject> cache = new ArrayList\u003C>(); \u002F\u002F static = GC root\n\u002F\u002F anything added here lives for the life of the class loader\n",[59,667,668,691],{"__ignoreMap":72},[76,669,670,673,676,678,681,683,685,688],{"class":78,"line":79},[76,671,672],{"class":82},"static",[76,674,675],{"class":90}," List\u003C",[76,677,478],{"class":82},[76,679,680],{"class":90},"> cache ",[76,682,103],{"class":82},[76,684,125],{"class":82},[76,686,687],{"class":90}," ArrayList\u003C>(); ",[76,689,690],{"class":113},"\u002F\u002F static = GC root\n",[76,692,693],{"class":78,"line":94},[76,694,695],{"class":113},"\u002F\u002F anything added here lives for the life of the class loader\n",[15,697,698],{},"Static collections that grow without bound are the most common source of leaks in\nlong-running services.",[10,700,702],{"id":701},"diagnosing-outofmemoryerror","Diagnosing OutOfMemoryError",[15,704,705,706,709],{},"When the JVM throws ",[59,707,708],{},"OutOfMemoryError: Java heap space",", the heap is full even after GC.\nThe fastest path to diagnosis:",[67,711,713],{"className":380,"code":712,"language":382,"meta":72,"style":72},"# Enable automatic heap dump when OOM occurs:\njava -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=\u002Ftmp\u002Fdump.hprof MyApp\n\n# Manual dump of a running process:\njmap -dump:live,format=b,file=\u002Ftmp\u002Fdump.hprof \u003Cpid>\n",[59,714,715,720,733,739,744],{"__ignoreMap":72},[76,716,717],{"class":78,"line":79},[76,718,719],{"class":113},"# Enable automatic heap dump when OOM occurs:\n",[76,721,722,724,727,730],{"class":78,"line":94},[76,723,71],{"class":86},[76,725,726],{"class":106}," -XX:+HeapDumpOnOutOfMemoryError",[76,728,729],{"class":106}," -XX:HeapDumpPath=\u002Ftmp\u002Fdump.hprof",[76,731,732],{"class":134}," MyApp\n",[76,734,735],{"class":78,"line":117},[76,736,738],{"emptyLinePlaceholder":737},true,"\n",[76,740,741],{"class":78,"line":144},[76,742,743],{"class":113},"# Manual dump of a running process:\n",[76,745,746,749,752,755,758,761],{"class":78,"line":150},[76,747,748],{"class":86},"jmap",[76,750,751],{"class":106}," -dump:live,format=b,file=\u002Ftmp\u002Fdump.hprof",[76,753,754],{"class":82}," \u003C",[76,756,757],{"class":134},"pi",[76,759,760],{"class":90},"d",[76,762,763],{"class":82},">\n",[15,765,766,767,770,771,774,775,778,779,782],{},"Open the dump in ",[35,768,769],{},"Eclipse MAT"," and run \"Leak Suspects\". The ",[35,772,773],{},"dominator tree"," shows the\nobjects retaining the most memory; the ",[35,776,777],{},"shortest path to GC root"," shows ",[19,780,781],{},"why"," they are\nretained. That path almost always points directly at the bug — an unbounded static\ncollection, a listener that was never removed, or a cache with no eviction policy.",[10,784,786],{"id":785},"soft-weak-and-phantom-references","Soft, weak, and phantom references",[15,788,789],{},"Java's reference types let you hold objects without preventing GC:",[418,791,792,805],{},[421,793,794],{},[424,795,796,799,802],{},[427,797,798],{},"Type",[427,800,801],{},"GC clears it",[427,803,804],{},"Typical use",[437,806,807,820,836],{},[424,808,809,814,817],{},[442,810,811],{},[59,812,813],{},"SoftReference\u003CT>",[442,815,816],{},"Only when JVM needs memory (before OOM)",[442,818,819],{},"Memory-sensitive caches",[424,821,822,827,830],{},[442,823,824],{},[59,825,826],{},"WeakReference\u003CT>",[442,828,829],{},"At any GC cycle",[442,831,832,835],{},[59,833,834],{},"WeakHashMap",", canonicalizing maps",[424,837,838,843,846],{},[442,839,840],{},[59,841,842],{},"PhantomReference\u003CT>",[442,844,845],{},"After finalization, before reclaim",[442,847,848],{},"Post-mortem cleanup",[67,850,852],{"className":69,"code":851,"language":71,"meta":72,"style":72},"SoftReference\u003Cbyte[]> cache = new SoftReference\u003C>(new byte[1024 * 1024]);\nbyte[] data = cache.get(); \u002F\u002F null if GC already cleared it\nif (data == null) data = reload();\n",[59,853,854,892,913],{"__ignoreMap":72},[76,855,856,859,862,865,867,869,872,874,877,880,883,886,889],{"class":78,"line":79},[76,857,858],{"class":90},"SoftReference\u003C",[76,860,861],{"class":82},"byte",[76,863,864],{"class":90},"[]> cache ",[76,866,103],{"class":82},[76,868,125],{"class":82},[76,870,871],{"class":90}," SoftReference\u003C>(",[76,873,61],{"class":82},[76,875,876],{"class":82}," byte",[76,878,879],{"class":90},"[",[76,881,882],{"class":106},"1024",[76,884,885],{"class":82}," *",[76,887,888],{"class":106}," 1024",[76,890,891],{"class":90},"]);\n",[76,893,894,896,899,901,904,907,910],{"class":78,"line":94},[76,895,861],{"class":82},[76,897,898],{"class":90},"[] data ",[76,900,103],{"class":82},[76,902,903],{"class":90}," cache.",[76,905,906],{"class":86},"get",[76,908,909],{"class":90},"(); ",[76,911,912],{"class":113},"\u002F\u002F null if GC already cleared it\n",[76,914,915,918,921,924,927,930,932,935],{"class":78,"line":117},[76,916,917],{"class":82},"if",[76,919,920],{"class":90}," (data ",[76,922,923],{"class":82},"==",[76,925,926],{"class":106}," null",[76,928,929],{"class":90},") data ",[76,931,103],{"class":82},[76,933,934],{"class":86}," reload",[76,936,937],{"class":90},"();\n",[15,939,940,942],{},[59,941,834],{}," is often misunderstood: keys are weakly referenced, so an entry disappears as\nsoon as no strong reference to the key exists elsewhere — useful for metadata caches keyed\nby objects you don't own.",[10,944,946],{"id":945},"native-off-heap-memory","Native (off-heap) memory",[15,948,949,950,953],{},"Not all JVM memory lives on the heap. ",[35,951,952],{},"Native memory"," is allocated directly from the OS\nand is not subject to GC:",[418,955,956,966],{},[421,957,958],{},[424,959,960,963],{},[427,961,962],{},"Consumer",[427,964,965],{},"Notes",[437,967,968,978,985,993,1003],{},[424,969,970,973],{},[442,971,972],{},"Thread stacks",[442,974,975,976],{},"one per thread, sized by ",[59,977,220],{},[424,979,980,982],{},[442,981,365],{},[442,983,984],{},"class metadata",[424,986,987,990],{},[442,988,989],{},"JIT code cache",[442,991,992],{},"compiled native machine code",[424,994,995,998],{},[442,996,997],{},"Direct ByteBuffers",[442,999,1000],{},[59,1001,1002],{},"ByteBuffer.allocateDirect()",[424,1004,1005,1008],{},[442,1006,1007],{},"GC internal structures",[442,1009,1010],{},"card tables, remembered sets",[15,1012,1013,1014,1017,1018,489,1021,1024,1025,1028],{},"If a process's resident set size (RSS) grows well beyond ",[59,1015,1016],{},"-Xmx",", the culprit is native\nmemory. Use ",[35,1019,1020],{},"Native Memory Tracking",[59,1022,1023],{},"-XX:NativeMemoryTracking=summary",") and\n",[59,1026,1027],{},"jcmd \u003Cpid> VM.native_memory summary"," to break it down.",[10,1030,1032],{"id":1031},"key-flags-at-a-glance","Key flags at a glance",[418,1034,1035,1045],{},[421,1036,1037],{},[424,1038,1039,1042],{},[427,1040,1041],{},"Flag",[427,1043,1044],{},"Effect",[437,1046,1047,1057,1066,1075,1084,1093,1103],{},[424,1048,1049,1054],{},[442,1050,1051],{},[59,1052,1053],{},"-Xms",[442,1055,1056],{},"Initial heap size",[424,1058,1059,1063],{},[442,1060,1061],{},[59,1062,1016],{},[442,1064,1065],{},"Maximum heap size",[424,1067,1068,1072],{},[442,1069,1070],{},[59,1071,220],{},[442,1073,1074],{},"Thread stack size",[424,1076,1077,1081],{},[442,1078,1079],{},[59,1080,376],{},[442,1082,1083],{},"Cap on Metaspace",[424,1085,1086,1090],{},[442,1087,1088],{},[59,1089,492],{},[442,1091,1092],{},"32-bit refs (default ≤ 32 GB heap)",[424,1094,1095,1100],{},[442,1096,1097],{},[59,1098,1099],{},"-XX:+HeapDumpOnOutOfMemoryError",[442,1101,1102],{},"Auto heap dump on OOM",[424,1104,1105,1109],{},[442,1106,1107],{},[59,1108,1023],{},[442,1110,1111],{},"Enable native memory tracking",[10,1113,1115],{"id":1114},"recap","Recap",[15,1117,45,1118,1120,1121,1123,1124,1127,1128,1130,1131,1134,1135,1138,1139,1142,1143,42],{},[35,1119,37],{}," is a per-thread, frame-based region for method-local data; the ",[35,1122,41],{}," is\nthe shared region managed by the GC. The heap is ",[35,1125,1126],{},"generational"," (Eden → Survivor → Old\nGen) to exploit the observation that most objects die young. ",[35,1129,365],{}," holds class\nmetadata in native memory. ",[35,1132,1133],{},"Escape analysis"," and ",[35,1136,1137],{},"TLABs"," make allocation cheap. Memory\nleaks in Java are objects still reachable from a ",[35,1140,1141],{},"GC root"," — trace them with a heap dump\nand Eclipse MAT. When native memory grows suspiciously large, reach for\n",[59,1144,1145],{},"-XX:NativeMemoryTracking",[1147,1148,1149],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":72,"searchDepth":94,"depth":94,"links":1151},[1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166],{"id":12,"depth":94,"text":13},{"id":29,"depth":94,"text":30},{"id":173,"depth":94,"text":174},{"id":213,"depth":94,"text":214},{"id":291,"depth":94,"text":292},{"id":354,"depth":94,"text":355},{"id":408,"depth":94,"text":409},{"id":500,"depth":94,"text":501},{"id":599,"depth":94,"text":600},{"id":627,"depth":94,"text":628},{"id":701,"depth":94,"text":702},{"id":785,"depth":94,"text":786},{"id":945,"depth":94,"text":946},{"id":1031,"depth":94,"text":1032},{"id":1114,"depth":94,"text":1115},"A complete guide to JVM memory — stack vs heap, generational heap regions, Metaspace, escape analysis, TLABs, GC roots, object headers, and how to diagnose OutOfMemoryError and StackOverflowError in production.","medium","md","Java",{},"\u002Fblog\u002Fjava-jvm-memory-heap-stack","\u002Fjava\u002Fjvm-internals\u002Fmemory-heap-stack",{"title":5,"description":1167},"blog\u002Fjava-jvm-memory-heap-stack","Memory — Heap & Stack","JVM Internals","jvm-internals","2026-06-20","PcFKLJnOvsr8L4agqo5XnOM8GCOcJYQ6VJ_lP_DxPhk",1782244089407]