[{"data":1,"prerenderedAt":1453},["ShallowReactive",2],{"post-document:\u002Fjava\u002Fjvm\u002F2026\u002F08\u002F10\u002Fjava-execution-memory\u002F":3},{"id":4,"title":5,"body":6,"categories":1432,"date":1434,"description":1435,"extension":1436,"image":1437,"key_concepts":1437,"last_modified_at":1437,"legacyPath":1438,"meta":1439,"navigation":633,"part":1441,"path":1442,"published":633,"robots":1437,"seo":1443,"series":1444,"stem":1445,"strengths":1437,"summary":1437,"tags":1446,"tradeoffs":1437,"__hash__":1452},"posts\u002Fposts\u002FBackend\u002FJAVA\u002Fjvm\u002F2026-08-10-java-execution-memory.md","Java 실행과 JVM Part 2: 메모리와 데이터 흐름",{"type":7,"value":8,"toc":1416},"minimark",[9,13,17,22,27,71,75,116,123,149,159,163,166,174,216,262,271,275,278,311,337,341,344,347,477,480,483,503,506,512,516,541,545,548,552,555,558,575,579,585,589,592,598,602,605,664,668,747,804,808,814,842,848,870,879,919,945,949,952,1036,1043,1067,1087,1091,1095,1117,1132,1146,1150,1153,1168,1171,1186,1190,1193,1257,1277,1286,1294,1297,1361,1370,1376,1380,1386,1412],[10,11,5],"h2",{"id":12},"java-실행과-jvm-part-2-메모리와-데이터-흐름",[14,15,16],"p",{},"Java 프로그램이 어떻게 실행되는지, 변수와 객체가 메모리에 어떻게 연결되는지, 그리고 문자열과 멀티스레드를 어떻게 다루는지 한 번에 정리한다.",[18,19,21],"h3",{"id":20},"_1-java-개발-환경","1. Java 개발 환경",[23,24,26],"h4",{"id":25},"필요한-도구-설치","필요한 도구 설치",[28,29,34],"pre",{"className":30,"code":31,"language":32,"meta":33,"style":33},"language-bash shiki shiki-themes github-light github-dark","brew install jq curl maven gradle node git kubectl\n","bash","",[35,36,37],"code",{"__ignoreMap":33},[38,39,42,46,50,53,56,59,62,65,68],"span",{"class":40,"line":41},"line",1,[38,43,45],{"class":44},"sScJk","brew",[38,47,49],{"class":48},"sZZnC"," install",[38,51,52],{"class":48}," jq",[38,54,55],{"class":48}," curl",[38,57,58],{"class":48}," maven",[38,60,61],{"class":48}," gradle",[38,63,64],{"class":48}," node",[38,66,67],{"class":48}," git",[38,69,70],{"class":48}," kubectl\n",[23,72,74],{"id":73},"java-21-설치와-환경-변수-설정","Java 21 설치와 환경 변수 설정",[28,76,78],{"className":30,"code":77,"language":32,"meta":33,"style":33},"brew install openjdk@21\njava --version\nexport JAVA_HOME=\u002Fopt\u002Fhomebrew\u002Fopt\u002Fopenjdk@21\n",[35,79,80,89,99],{"__ignoreMap":33},[38,81,82,84,86],{"class":40,"line":41},[38,83,45],{"class":44},[38,85,49],{"class":48},[38,87,88],{"class":48}," openjdk@21\n",[38,90,92,95],{"class":40,"line":91},2,[38,93,94],{"class":44},"java",[38,96,98],{"class":97},"sj4cs"," --version\n",[38,100,102,106,110,113],{"class":40,"line":101},3,[38,103,105],{"class":104},"szBVR","export",[38,107,109],{"class":108},"sVt8B"," JAVA_HOME",[38,111,112],{"class":104},"=",[38,114,115],{"class":108},"\u002Fopt\u002Fhomebrew\u002Fopt\u002Fopenjdk@21\n",[14,117,118,119,122],{},"매번 설정하지 않으려면 ",[35,120,121],{},"~\u002F.zshrc","에 추가한다.",[28,124,126],{"className":30,"code":125,"language":32,"meta":33,"style":33},"echo 'export JAVA_HOME=\u002Fopt\u002Fhomebrew\u002Fopt\u002Fopenjdk@21' >> ~\u002F.zshrc\nsource ~\u002F.zshrc\n",[35,127,128,142],{"__ignoreMap":33},[38,129,130,133,136,139],{"class":40,"line":41},[38,131,132],{"class":97},"echo",[38,134,135],{"class":48}," 'export JAVA_HOME=\u002Fopt\u002Fhomebrew\u002Fopt\u002Fopenjdk@21'",[38,137,138],{"class":104}," >>",[38,140,141],{"class":48}," ~\u002F.zshrc\n",[38,143,144,147],{"class":40,"line":91},[38,145,146],{"class":97},"source",[38,148,141],{"class":48},[14,150,151,154,155,158],{},[35,152,153],{},"JAVA_HOME","은 Java가 설치된 위치를 알려 주는 환경 변수다. 실제 경로는 설치 환경에 따라 다를 수 있으므로 ",[35,156,157],{},"brew --prefix openjdk@21","로 확인할 수 있다.",[18,160,162],{"id":161},"_2-java-코드가-실행되는-과정","2. Java 코드가 실행되는 과정",[14,164,165],{},"Java는 소스 코드를 바로 실행하지 않는다.",[28,167,172],{"className":168,"code":170,"language":171,"meta":33},[169],"language-text","App.java\n   │  javac 컴파일\n   ▼\nApp.class  ← JVM이 이해하는 바이트코드\n   │  java 실행\n   ▼\nJVM이 main() 메서드를 찾아 실행\n","text",[35,173,170],{"__ignoreMap":33},[28,175,177],{"className":30,"code":176,"language":32,"meta":33,"style":33},"mkdir -p bin\njavac -d bin src\u002FApp.java\njava -cp bin App\n",[35,178,179,190,204],{"__ignoreMap":33},[38,180,181,184,187],{"class":40,"line":41},[38,182,183],{"class":44},"mkdir",[38,185,186],{"class":97}," -p",[38,188,189],{"class":48}," bin\n",[38,191,192,195,198,201],{"class":40,"line":91},[38,193,194],{"class":44},"javac",[38,196,197],{"class":97}," -d",[38,199,200],{"class":48}," bin",[38,202,203],{"class":48}," src\u002FApp.java\n",[38,205,206,208,211,213],{"class":40,"line":101},[38,207,94],{"class":44},[38,209,210],{"class":97}," -cp",[38,212,200],{"class":48},[38,214,215],{"class":48}," App\n",[217,218,219,233,243,250,256],"ul",{},[220,221,222,224,225,228,229,232],"li",{},[35,223,194],{},": ",[35,226,227],{},".java","를 ",[35,230,231],{},".class","로 컴파일한다.",[220,234,235,238,239,242],{},[35,236,237],{},"-d bin",": 컴파일 결과를 ",[35,240,241],{},"bin"," 폴더에 저장한다.",[220,244,245,224,247,249],{},[35,246,94],{},[35,248,231],{}," 파일을 JVM에서 실행한다.",[220,251,252,255],{},[35,253,254],{},"-cp bin",": 클래스를 찾을 경로를 지정한다.",[220,257,258,261],{},[35,259,260],{},"main()",": Java 애플리케이션의 시작 메서드다.",[14,263,264,265,267,268,270],{},"즉, JVM이 ",[35,266,194],{},"를 실행하는 것이 아니라 ",[35,269,194],{},"가 만든 바이트코드를 JVM이 실행한다.",[18,272,274],{"id":273},"_3-java-프로그램의-기본-구조","3. Java 프로그램의 기본 구조",[14,276,277],{},"Java 코드는 보통 클래스 안에 작성한다.",[28,279,282],{"className":280,"code":281,"language":94,"meta":33,"style":33},"language-java shiki shiki-themes github-light github-dark","public class HelloSkala {\n    public static void main(String[] args) {\n        System.out.println(\"Hello, Skala!\");\n    }\n}\n",[35,283,284,289,294,299,305],{"__ignoreMap":33},[38,285,286],{"class":40,"line":41},[38,287,288],{},"public class HelloSkala {\n",[38,290,291],{"class":40,"line":91},[38,292,293],{},"    public static void main(String[] args) {\n",[38,295,296],{"class":40,"line":101},[38,297,298],{},"        System.out.println(\"Hello, Skala!\");\n",[38,300,302],{"class":40,"line":301},4,[38,303,304],{},"    }\n",[38,306,308],{"class":40,"line":307},5,[38,309,310],{},"}\n",[217,312,313,319,325,331],{},[220,314,315,318],{},[35,316,317],{},"class",": 데이터와 기능을 묶는 기본 단위다.",[220,320,321,324],{},[35,322,323],{},"main",": 프로그램이 시작되는 메서드다.",[220,326,327,330],{},[35,328,329],{},"System.out.println",": 콘솔에 값을 출력한다.",[220,332,333,336],{},[35,334,335],{},"static",": 객체를 만들지 않아도 클래스에 소속된 형태로 사용할 수 있다는 뜻이다.",[18,338,340],{"id":339},"_4-기본형과-참조형","4. 기본형과 참조형",[23,342,343],{"id":343},"기본형",[14,345,346],{},"기본형은 숫자, 문자, 참·거짓처럼 값 자체를 저장하는 타입이다.",[348,349,350,366],"table",{},[351,352,353],"thead",{},[354,355,356,360,363],"tr",{},[357,358,359],"th",{},"타입",[357,361,362],{},"의미",[357,364,365],{},"크기",[367,368,369,383,396,409,422,434,446,458],"tbody",{},[354,370,371,377,380],{},[372,373,374],"td",{},[35,375,376],{},"byte",[372,378,379],{},"작은 정수",[372,381,382],{},"1 byte",[354,384,385,390,393],{},[372,386,387],{},[35,388,389],{},"short",[372,391,392],{},"정수",[372,394,395],{},"2 bytes",[354,397,398,403,406],{},[372,399,400],{},[35,401,402],{},"int",[372,404,405],{},"일반적인 정수",[372,407,408],{},"4 bytes",[354,410,411,416,419],{},[372,412,413],{},[35,414,415],{},"long",[372,417,418],{},"큰 정수",[372,420,421],{},"8 bytes",[354,423,424,429,432],{},[372,425,426],{},[35,427,428],{},"float",[372,430,431],{},"실수",[372,433,408],{},[354,435,436,441,444],{},[372,437,438],{},[35,439,440],{},"double",[372,442,443],{},"정밀한 실수",[372,445,421],{},[354,447,448,453,456],{},[372,449,450],{},[35,451,452],{},"char",[372,454,455],{},"문자 하나",[372,457,395],{},[354,459,460,465,474],{},[372,461,462],{},[35,463,464],{},"boolean",[372,466,467,470,471],{},[35,468,469],{},"true"," 또는 ",[35,472,473],{},"false",[372,475,476],{},"JVM 구현에 따라 다름",[23,478,479],{"id":479},"참조형",[14,481,482],{},"참조형 변수는 객체 본체를 직접 담는 것이 아니라, 객체를 가리키는 참조값을 저장한다.",[28,484,486],{"className":280,"code":485,"language":94,"meta":33,"style":33},"int age = 20;              \u002F\u002F age에 값 20 저장\nString name = \"Skala\";     \u002F\u002F name에는 String 객체를 가리키는 참조값 저장\nint[] scores = {90, 80};   \u002F\u002F scores에는 배열 객체를 가리키는 참조값 저장\n",[35,487,488,493,498],{"__ignoreMap":33},[38,489,490],{"class":40,"line":41},[38,491,492],{},"int age = 20;              \u002F\u002F age에 값 20 저장\n",[38,494,495],{"class":40,"line":91},[38,496,497],{},"String name = \"Skala\";     \u002F\u002F name에는 String 객체를 가리키는 참조값 저장\n",[38,499,500],{"class":40,"line":101},[38,501,502],{},"int[] scores = {90, 80};   \u002F\u002F scores에는 배열 객체를 가리키는 참조값 저장\n",[14,504,505],{},"쉽게 말하면 다음과 같다.",[28,507,510],{"className":508,"code":509,"language":171,"meta":33},[169],"name ── 참조값 ──▶ \"Skala\" String 객체\nage  ── 값 20\n",[35,511,509],{"__ignoreMap":33},[23,513,515],{"id":514},"주의-기본값과-지역-변수","주의: 기본값과 지역 변수",[217,517,518,538],{},[220,519,520,521,523,524,527,528,530,531,533,534,537],{},"클래스의 필드에는 선언하지 않아도 기본값이 들어간다. ",[35,522,402],{},"는 ",[35,525,526],{},"0",", ",[35,529,464],{},"은 ",[35,532,473],{},", 참조형은 ",[35,535,536],{},"null","이다.",[220,539,540],{},"메서드 안의 지역 변수는 자동으로 기본값이 들어가지 않는다. 사용하기 전에 반드시 값을 대입해야 한다.",[18,542,544],{"id":543},"_5-jvm-메모리-구조","5. JVM 메모리 구조",[14,546,547],{},"메모리를 설명할 때 자주 등장하는 영역은 Stack, Heap, Metaspace다.",[23,549,551],{"id":550},"stack","Stack",[14,553,554],{},"메서드가 호출될 때마다 해당 메서드의 Stack Frame이 만들어진다. 메서드가 끝나면 Frame도 사라진다.",[14,556,557],{},"Stack Frame에는 다음과 같은 정보가 들어간다.",[217,559,560,566,572],{},[220,561,562,565],{},[35,563,564],{},"Local Variables",": 지역 변수와 매개변수",[220,567,568,571],{},[35,569,570],{},"Operand Stack",": 바이트코드 연산에 잠시 사용하는 값",[220,573,574],{},"반환 주소 등 메서드 실행에 필요한 정보",[23,576,578],{"id":577},"heap","Heap",[14,580,581,584],{},[35,582,583],{},"new","로 만든 객체와 배열의 본체가 저장되는 영역이다. 객체는 메서드가 끝난 뒤에도 다른 곳에서 참조하고 있다면 계속 살아 있을 수 있다. 더 이상 참조되지 않는 객체는 Garbage Collector가 정리한다.",[23,586,588],{"id":587},"metaspace","Metaspace",[14,590,591],{},"클래스의 이름, 메서드 정보, 필드 정보, 바이트코드 등 클래스 구조에 대한 메타데이터가 저장되는 영역이다.",[14,593,594,597],{},[35,595,596],{},"java.lang.Class"," 객체도 Heap에 존재하며, Metaspace의 클래스 메타데이터와 연결되어 있다고 이해하면 된다.",[18,599,601],{"id":600},"_6-코드로-보는-데이터-흐름","6. 코드로 보는 데이터 흐름",[14,603,604],{},"다음 코드를 기준으로 각 값의 위치를 살펴보자.",[28,606,608],{"className":280,"code":607,"language":94,"meta":33,"style":33},"class Person {\n    static int count;\n    int age = 20;\n}\n\nvoid foo() {\n    int x = 10;\n    Person person = new Person();\n    int result = person.age + x;\n}\n",[35,609,610,615,620,625,629,635,641,647,653,659],{"__ignoreMap":33},[38,611,612],{"class":40,"line":41},[38,613,614],{},"class Person {\n",[38,616,617],{"class":40,"line":91},[38,618,619],{},"    static int count;\n",[38,621,622],{"class":40,"line":101},[38,623,624],{},"    int age = 20;\n",[38,626,627],{"class":40,"line":301},[38,628,310],{},[38,630,631],{"class":40,"line":307},[38,632,634],{"emptyLinePlaceholder":633},true,"\n",[38,636,638],{"class":40,"line":637},6,[38,639,640],{},"void foo() {\n",[38,642,644],{"class":40,"line":643},7,[38,645,646],{},"    int x = 10;\n",[38,648,650],{"class":40,"line":649},8,[38,651,652],{},"    Person person = new Person();\n",[38,654,656],{"class":40,"line":655},9,[38,657,658],{},"    int result = person.age + x;\n",[38,660,662],{"class":40,"line":661},10,[38,663,310],{},[23,665,667],{"id":666},"실행-순서","실행 순서",[669,670,671,680,694,704,710,724,735],"ol",{},[220,672,673,676,677,679],{},[35,674,675],{},"foo()","가 호출되면 ",[35,678,675],{}," 전용 Stack Frame이 만들어진다.",[220,681,682,685,686,689,690,693],{},[35,683,684],{},"int x = 10","의 ",[35,687,688],{},"x","는 Local Variables 영역에 값 ",[35,691,692],{},"10","으로 저장된다.",[220,695,696,699,700,703],{},[35,697,698],{},"new Person()","이 Heap에 ",[35,701,702],{},"Person"," 객체를 만든다.",[220,705,706,709],{},[35,707,708],{},"person","은 Stack에 저장되고, Heap 객체를 가리키는 참조값을 가진다.",[220,711,712,685,715,718,719,685,721,723],{},[35,713,714],{},"person.age",[35,716,717],{},"20","과 ",[35,720,688],{},[35,722,692],{},"이 Operand Stack으로 전달되어 계산된다.",[220,725,726,727,730,731,734],{},"계산 결과 ",[35,728,729],{},"30","이 지역 변수 ",[35,732,733],{},"result","에 저장된다.",[220,736,737,739,740,527,742,527,744,746],{},[35,738,675],{},"가 끝나면 ",[35,741,688],{},[35,743,708],{},[35,745,733],{},"가 들어 있던 Stack Frame은 사라진다.",[28,748,752],{"className":749,"code":750,"language":751,"meta":33,"style":33},"language-mermaid shiki shiki-themes github-light github-dark","flowchart LR\n    Call[\"foo() 호출\"] --> Frame[\"foo() Stack Frame\"]\n    Frame --> X[\"Local Variables\\nx = 10\"]\n    Frame --> P[\"Local Variables\\nperson = 참조값\"]\n    Frame --> R[\"Local Variables\\nresult = 30\"]\n    P -->|\"참조\"| Object[\"Heap\\nPerson 객체\"]\n    Object --> Age[\"age = 20\"]\n    Age --> Operand[\"Operand Stack\\n20 + 10\"]\n    X --> Operand\n    Operand --> R\n","mermaid",[35,753,754,759,764,769,774,779,784,789,794,799],{"__ignoreMap":33},[38,755,756],{"class":40,"line":41},[38,757,758],{},"flowchart LR\n",[38,760,761],{"class":40,"line":91},[38,762,763],{},"    Call[\"foo() 호출\"] --> Frame[\"foo() Stack Frame\"]\n",[38,765,766],{"class":40,"line":101},[38,767,768],{},"    Frame --> X[\"Local Variables\\nx = 10\"]\n",[38,770,771],{"class":40,"line":301},[38,772,773],{},"    Frame --> P[\"Local Variables\\nperson = 참조값\"]\n",[38,775,776],{"class":40,"line":307},[38,777,778],{},"    Frame --> R[\"Local Variables\\nresult = 30\"]\n",[38,780,781],{"class":40,"line":637},[38,782,783],{},"    P -->|\"참조\"| Object[\"Heap\\nPerson 객체\"]\n",[38,785,786],{"class":40,"line":643},[38,787,788],{},"    Object --> Age[\"age = 20\"]\n",[38,790,791],{"class":40,"line":649},[38,792,793],{},"    Age --> Operand[\"Operand Stack\\n20 + 10\"]\n",[38,795,796],{"class":40,"line":655},[38,797,798],{},"    X --> Operand\n",[38,800,801],{"class":40,"line":661},[38,802,803],{},"    Operand --> R\n",[23,805,807],{"id":806},"핵심-정리","핵심 정리",[28,809,812],{"className":810,"code":811,"language":171,"meta":33},[169],"person ─────────────▶ Heap의 Person 객체\n  Stack                  age = 20\n\nx = 10 ──┐\nage = 20 ─┴─▶ Operand Stack에서 20 + 10 계산\n                    │\n                    ▼\n              result = 30\n",[35,813,811],{"__ignoreMap":33},[217,815,816,821,826,832,839],{},[220,817,818,820],{},[35,819,708],{},": Stack의 지역 변수 슬롯에 참조값이 저장된다.",[220,822,823,825],{},[35,824,698],{},": Heap에 객체 본체가 만들어진다.",[220,827,828,831],{},[35,829,830],{},"age",": Person 객체의 인스턴스 필드이므로 Heap 객체 안에 저장된다.",[220,833,834,527,836,838],{},[35,835,688],{},[35,837,733],{},": 메서드의 지역 변수이므로 해당 Stack Frame의 Local Variables에 저장된다.",[220,840,841],{},"연산 중간값: Operand Stack을 사용한다.",[23,843,845,847],{"id":844},"static-필드는-어디에-있을까",[35,846,335],{}," 필드는 어디에 있을까?",[28,849,851],{"className":280,"code":850,"language":94,"meta":33,"style":33},"class Person {\n    static int count;\n    int age;\n}\n",[35,852,853,857,861,866],{"__ignoreMap":33},[38,854,855],{"class":40,"line":41},[38,856,614],{},[38,858,859],{"class":40,"line":91},[38,860,619],{},[38,862,863],{"class":40,"line":101},[38,864,865],{},"    int age;\n",[38,867,868],{"class":40,"line":301},[38,869,310],{},[14,871,872,874,875,878],{},[35,873,830],{},"는 각 객체마다 따로 존재하지만, ",[35,876,877],{},"count","는 Person 클래스 전체가 하나만 공유한다.",[28,880,882],{"className":749,"code":881,"language":751,"meta":33,"style":33},"flowchart TD\n    Loader[\"ClassLoader\"] --> Meta[\"Metaspace\\nPerson 클래스 메타데이터\"]\n    Loader --> ClassObject[\"Heap\\njava.lang.Class 객체\"]\n    ClassObject --> Static[\"Person.count\\n클래스 공용 데이터\"]\n    ClassObject -. \"클래스 구조와 연결\" .-> Meta\n    Instance1[\"Heap\\nPerson 객체 1: age\"]\n    Instance2[\"Heap\\nPerson 객체 2: age\"]\n",[35,883,884,889,894,899,904,909,914],{"__ignoreMap":33},[38,885,886],{"class":40,"line":41},[38,887,888],{},"flowchart TD\n",[38,890,891],{"class":40,"line":91},[38,892,893],{},"    Loader[\"ClassLoader\"] --> Meta[\"Metaspace\\nPerson 클래스 메타데이터\"]\n",[38,895,896],{"class":40,"line":101},[38,897,898],{},"    Loader --> ClassObject[\"Heap\\njava.lang.Class 객체\"]\n",[38,900,901],{"class":40,"line":301},[38,902,903],{},"    ClassObject --> Static[\"Person.count\\n클래스 공용 데이터\"]\n",[38,905,906],{"class":40,"line":307},[38,907,908],{},"    ClassObject -. \"클래스 구조와 연결\" .-> Meta\n",[38,910,911],{"class":40,"line":637},[38,912,913],{},"    Instance1[\"Heap\\nPerson 객체 1: age\"]\n",[38,915,916],{"class":40,"line":643},[38,917,918],{},"    Instance2[\"Heap\\nPerson 객체 2: age\"]\n",[217,920,921,927,935],{},[220,922,923,924,926],{},"인스턴스 필드 ",[35,925,830],{},"는 객체마다 Heap에 하나씩 생긴다.",[220,928,929,931,932,934],{},[35,930,335],{}," 필드 ",[35,933,877],{},"는 객체가 아니라 클래스에 소속되며 모든 인스턴스가 공유한다.",[220,936,937,938,940,941,944],{},"정확한 물리적 위치와 구현 방식은 JVM에 따라 다를 수 있다. 따라서 ",[35,939,335],{}," 필드를 무조건 “Heap의 ",[35,942,943],{},"Class"," 객체 안에 있다”고 단정하기보다, “클래스 단위로 관리되고 클래스 메타데이터와 연결된다”고 이해하는 편이 안전하다.",[18,946,948],{"id":947},"_7-변수-저장-위치를-판단하는-방법","7. 변수 저장 위치를 판단하는 방법",[14,950,951],{},"“기본형은 Stack, 참조형은 Heap”이라고 외우면 틀릴 수 있다. 변수의 종류와 실행 위치를 함께 봐야 한다.",[348,953,954,967],{},[351,955,956],{},[354,957,958,961,964],{},[357,959,960],{},"코드",[357,962,963],{},"무엇인가?",[357,965,966],{},"쉽게 이해하면",[367,968,969,982,995,1007,1023],{},[354,970,971,976,979],{},[372,972,973,975],{},[35,974,684],{}," in method",[372,977,978],{},"지역 기본형 변수",[372,980,981],{},"Stack Frame에 값 저장",[354,983,984,989,992],{},[372,985,986,975],{},[35,987,988],{},"Person person",[372,990,991],{},"지역 참조형 변수",[372,993,994],{},"Stack Frame에 참조값 저장",[354,996,997,1001,1004],{},[372,998,999],{},[35,1000,698],{},[372,1002,1003],{},"객체 본체",[372,1005,1006],{},"Heap에 저장",[354,1008,1009,1017,1020],{},[372,1010,1011,1014,1015],{},[35,1012,1013],{},"int age"," in ",[35,1016,702],{},[372,1018,1019],{},"인스턴스 필드",[372,1021,1022],{},"Heap 객체 안에 저장",[354,1024,1025,1030,1033],{},[372,1026,1027],{},[35,1028,1029],{},"static int count",[372,1031,1032],{},"클래스 필드",[372,1034,1035],{},"클래스 단위로 공유",[14,1037,1038,1039,1042],{},"예를 들어 다음 코드에서 ",[35,1040,1041],{},"score","는 지역 변수가 아니라 인스턴스 필드다.",[28,1044,1046],{"className":280,"code":1045,"language":94,"meta":33,"style":33},"class Student {\n    int score = 100;\n    String name = \"Min\";\n}\n",[35,1047,1048,1053,1058,1063],{"__ignoreMap":33},[38,1049,1050],{"class":40,"line":41},[38,1051,1052],{},"class Student {\n",[38,1054,1055],{"class":40,"line":91},[38,1056,1057],{},"    int score = 100;\n",[38,1059,1060],{"class":40,"line":101},[38,1061,1062],{},"    String name = \"Min\";\n",[38,1064,1065],{"class":40,"line":301},[38,1066,310],{},[14,1068,1069,1072,1073,1075,1076,1079,1080,685,1083,1086],{},[35,1070,1071],{},"Student student = new Student()","로 객체를 만들면 ",[35,1074,1041],{},"와 ",[35,1077,1078],{},"name","은 Student Heap 객체의 일부가 된다. 반대로 ",[35,1081,1082],{},"void study() { int minutes = 30; }",[35,1084,1085],{},"minutes","는 메서드의 지역 변수이므로 Stack Frame에서 관리된다.",[18,1088,1090],{"id":1089},"_8-불변-객체와-wrapper-클래스","8. 불변 객체와 Wrapper 클래스",[23,1092,1094],{"id":1093},"불변-객체","불변 객체",[14,1096,1097,1098,527,1101,527,1104,527,1107,527,1110,527,1113,1116],{},"불변 객체는 생성된 뒤 내부 값을 바꿀 수 없는 객체다. 대표적으로 ",[35,1099,1100],{},"String",[35,1102,1103],{},"Integer",[35,1105,1106],{},"Long",[35,1108,1109],{},"Double",[35,1111,1112],{},"Character",[35,1114,1115],{},"Boolean","이 있다.",[28,1118,1120],{"className":280,"code":1119,"language":94,"meta":33,"style":33},"String text = \"Java\";\ntext = text + \"!\";\n",[35,1121,1122,1127],{"__ignoreMap":33},[38,1123,1124],{"class":40,"line":41},[38,1125,1126],{},"String text = \"Java\";\n",[38,1128,1129],{"class":40,"line":91},[38,1130,1131],{},"text = text + \"!\";\n",[14,1133,1134,1135,1138,1139,1142,1143,1145],{},"위 코드는 기존 String 객체에 ",[35,1136,1137],{},"!","를 붙이는 것이 아니다. ",[35,1140,1141],{},"\"Java!\"","라는 새로운 String 객체를 만들고 ",[35,1144,171],{},"가 새 객체를 가리키게 된다.",[23,1147,1149],{"id":1148},"wrapper-클래스와-오토박싱","Wrapper 클래스와 오토박싱",[14,1151,1152],{},"Wrapper 클래스는 기본형을 객체처럼 사용할 수 있게 감싼 클래스다.",[28,1154,1156],{"className":280,"code":1155,"language":94,"meta":33,"style":33},"Integer number = 10; \u002F\u002F int 10이 Integer 객체로 자동 변환\nnumber = number + 1;  \u002F\u002F 값을 바꾸는 대신 새 Integer 객체를 가리킴\n",[35,1157,1158,1163],{"__ignoreMap":33},[38,1159,1160],{"class":40,"line":41},[38,1161,1162],{},"Integer number = 10; \u002F\u002F int 10이 Integer 객체로 자동 변환\n",[38,1164,1165],{"class":40,"line":91},[38,1166,1167],{},"number = number + 1;  \u002F\u002F 값을 바꾸는 대신 새 Integer 객체를 가리킴\n",[14,1169,1170],{},"컬렉션은 객체만 저장할 수 있으므로 다음처럼 Wrapper 클래스를 사용한다.",[28,1172,1174],{"className":280,"code":1173,"language":94,"meta":33,"style":33},"List\u003CInteger> scores = new ArrayList\u003C>();\nscores.add(100);\n",[35,1175,1176,1181],{"__ignoreMap":33},[38,1177,1178],{"class":40,"line":41},[38,1179,1180],{},"List\u003CInteger> scores = new ArrayList\u003C>();\n",[38,1182,1183],{"class":40,"line":91},[38,1184,1185],{},"scores.add(100);\n",[18,1187,1189],{"id":1188},"_9-stringbuilder와-stringbuffer","9. StringBuilder와 StringBuffer",[14,1191,1192],{},"String은 불변이므로 문자열을 반복해서 더하면 중간 객체가 많이 만들어질 수 있다. 이때 문자열을 수정할 수 있는 버퍼를 사용한다.",[348,1194,1195,1212],{},[351,1196,1197],{},[354,1198,1199,1202,1207],{},[357,1200,1201],{},"구분",[357,1203,1204],{},[35,1205,1206],{},"StringBuilder",[357,1208,1209],{},[35,1210,1211],{},"StringBuffer",[367,1213,1214,1224,1235,1246],{},[354,1215,1216,1219,1222],{},[372,1217,1218],{},"문자열 수정",[372,1220,1221],{},"가능",[372,1223,1221],{},[354,1225,1226,1229,1232],{},[372,1227,1228],{},"동기화",[372,1230,1231],{},"하지 않음",[372,1233,1234],{},"메서드에 동기화 적용",[354,1236,1237,1240,1243],{},[372,1238,1239],{},"일반적인 속도",[372,1241,1242],{},"빠름",[372,1244,1245],{},"상대적으로 느림",[354,1247,1248,1251,1254],{},[372,1249,1250],{},"사용 상황",[372,1252,1253],{},"대부분의 단일 스레드 코드",[372,1255,1256],{},"여러 스레드가 같은 버퍼를 공유하는 경우",[28,1258,1260],{"className":280,"code":1259,"language":94,"meta":33,"style":33},"StringBuilder builder = new StringBuilder();\nbuilder.append(\"Hello\").append(\" \").append(\"Java\");\nString result = builder.toString();\n",[35,1261,1262,1267,1272],{"__ignoreMap":33},[38,1263,1264],{"class":40,"line":41},[38,1265,1266],{},"StringBuilder builder = new StringBuilder();\n",[38,1268,1269],{"class":40,"line":91},[38,1270,1271],{},"builder.append(\"Hello\").append(\" \").append(\"Java\");\n",[38,1273,1274],{"class":40,"line":101},[38,1275,1276],{},"String result = builder.toString();\n",[14,1278,1279,1280,1282,1283,1285],{},"실무에서는 공유하지 않는 문자열 조립에는 보통 ",[35,1281,1206],{},"를 사용한다. 여러 스레드가 하나의 버퍼를 직접 공유해야 하고 동기화가 필요하다면 ",[35,1284,1211],{},"를 고려한다.",[18,1287,1289,1290,1293],{"id":1288},"_10-synchronized와-공유-자원","10. ",[35,1291,1292],{},"synchronized","와 공유 자원",[14,1295,1296],{},"여러 스레드가 같은 값을 동시에 수정하면 실행 순서에 따라 결과가 달라질 수 있다. 이런 문제가 발생하는 코드를 임계 영역이라고 한다.",[28,1298,1300],{"className":280,"code":1299,"language":94,"meta":33,"style":33},"class BankAccount {\n    private int balance = 1000;\n\n    public synchronized void withdraw(int amount) {\n        if (balance >= amount) {\n            balance -= amount;\n            System.out.println(\"출금 성공: \" + amount);\n        } else {\n            System.out.println(\"잔액 부족\");\n        }\n    }\n}\n",[35,1301,1302,1307,1312,1316,1321,1326,1331,1336,1341,1346,1351,1356],{"__ignoreMap":33},[38,1303,1304],{"class":40,"line":41},[38,1305,1306],{},"class BankAccount {\n",[38,1308,1309],{"class":40,"line":91},[38,1310,1311],{},"    private int balance = 1000;\n",[38,1313,1314],{"class":40,"line":101},[38,1315,634],{"emptyLinePlaceholder":633},[38,1317,1318],{"class":40,"line":301},[38,1319,1320],{},"    public synchronized void withdraw(int amount) {\n",[38,1322,1323],{"class":40,"line":307},[38,1324,1325],{},"        if (balance >= amount) {\n",[38,1327,1328],{"class":40,"line":637},[38,1329,1330],{},"            balance -= amount;\n",[38,1332,1333],{"class":40,"line":643},[38,1334,1335],{},"            System.out.println(\"출금 성공: \" + amount);\n",[38,1337,1338],{"class":40,"line":649},[38,1339,1340],{},"        } else {\n",[38,1342,1343],{"class":40,"line":655},[38,1344,1345],{},"            System.out.println(\"잔액 부족\");\n",[38,1347,1348],{"class":40,"line":661},[38,1349,1350],{},"        }\n",[38,1352,1354],{"class":40,"line":1353},11,[38,1355,304],{},[38,1357,1359],{"class":40,"line":1358},12,[38,1360,310],{},[14,1362,1363,1366,1367,1369],{},[35,1364,1365],{},"withdraw()","에 ",[35,1368,1292],{},"를 붙이면 같은 계좌 객체를 대상으로 한 출금 메서드 실행에 한 번에 한 스레드만 들어간다. 따라서 잔액 확인과 차감이 중간에 끊기지 않도록 보호할 수 있다.",[14,1371,1372,1373,1375],{},"다만 ",[35,1374,1292],{},"는 모든 문제를 자동으로 해결하는 기능은 아니다. 어떤 객체를 잠그는지, 여러 메서드가 같은 공유 자원을 다루는지까지 함께 확인해야 한다.",[18,1377,1379],{"id":1378},"_11-마지막-요약","11. 마지막 요약",[28,1381,1384],{"className":1382,"code":1383,"language":171,"meta":33},[169],"소스 코드(.java)\n      │ javac\n      ▼\n바이트코드(.class)\n      │ JVM 실행\n      ▼\n┌────────────────────────────────────┐\n│ Stack      : 메서드 실행, 지역 변수   │\n│ Heap       : 객체와 배열의 본체       │\n│ Metaspace  : 클래스 구조 정보         │\n└────────────────────────────────────┘\n",[35,1385,1383],{"__ignoreMap":33},[217,1387,1388,1391,1394,1397,1400,1406,1409],{},[220,1389,1390],{},"기본형과 참조형은 “무조건 Stack과 Heap”으로 나누지 말고, 지역 변수인지 필드인지 먼저 확인한다.",[220,1392,1393],{},"지역 변수는 Stack Frame에서 관리되는 경우가 많다.",[220,1395,1396],{},"객체와 배열의 본체는 Heap에 저장된다.",[220,1398,1399],{},"참조형 지역 변수에는 객체 자체가 아니라 객체를 가리키는 참조값이 저장된다.",[220,1401,1402,1403,1405],{},"인스턴스 필드는 객체마다 존재하고, ",[35,1404,335],{}," 필드는 클래스 전체가 공유한다.",[220,1407,1408],{},"메서드 내부 계산에는 Operand Stack이 사용된다.",[220,1410,1411],{},"더 이상 참조되지 않는 Heap 객체는 Garbage Collector가 회수한다.",[1413,1414,1415],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}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);}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":33,"searchDepth":91,"depth":91,"links":1417},[1418],{"id":12,"depth":91,"text":5,"children":1419},[1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1431],{"id":20,"depth":101,"text":21},{"id":161,"depth":101,"text":162},{"id":273,"depth":101,"text":274},{"id":339,"depth":101,"text":340},{"id":543,"depth":101,"text":544},{"id":600,"depth":101,"text":601},{"id":947,"depth":101,"text":948},{"id":1089,"depth":101,"text":1090},{"id":1188,"depth":101,"text":1189},{"id":1288,"depth":101,"text":1430},"10. synchronized와 공유 자원",{"id":1378,"depth":101,"text":1379},[94,1433],"jvm","2026-08-10 10:00:00 +0900","Java 실행 환경부터 기본형과 참조형, Stack, Heap, Metaspace와 멀티스레드의 데이터 흐름을 정리한다.","md",null,"\u002Fjava\u002Fjvm\u002F2026\u002F08\u002F10\u002Fjava-execution-memory\u002F",{"layout":1440},"post","2","\u002Fposts\u002Fbackend\u002Fjava\u002Fjvm\u002F2026-08-10-java-execution-memory",{"title":5,"description":1435},"Java 실행과 JVM","posts\u002FBackend\u002FJAVA\u002Fjvm\u002F2026-08-10-java-execution-memory",[1447,1448,1449,551,578,1450,1206,1451],"Java","JDK","JVM","Thread","Synchronized","O-VaaoSLeofBy7W0FFSn6Y-XWlKNKf9F0lT4DuWSbtE",1788744784768]