티스토리 툴바


블로그 이미지
카라크라스

Leon.Kim의 공부하는 블로그입니다. mail - kalaklas@gmail.com twitter - @kalaklas

Rss feed Tistory
Java 2009/10/15 14:09

JVM Specification 을 간단히 리뷰해 보았습니다.

JVM Specification

아래의 글들은 밑의 사이트들을 참고하여 정리한 내용입니다.
{
. ClassLoader(http://java.sun.com/docs/books/tutorial/ext/basics/load.html)

. Inside Virtual Machine

(http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html)

- Startup

- Memory allocation(Stack & Queue)

- GC
}

JVM

Class Loader

○ Class Loader란?

Class Loader란 자바의 큰장점중의 하나로, Compile Time이 아닌 Run Time에 Class를 로딩할 수 있게 해주는 기술이다. 예를 들어, ClassA = new ClassA(); 라는 코드를 최초로 실행할때, JVM은 ClassA라는 Class를 Class Loader를 통해서, ClassA.class의 바이트 코드를 최초로 메모리에 로드하게 된다. Class Loader는 이처럼, Class의 바이트 코드를 FileSystem이나,Jar와 같은 Archieve또는, network socket(Applet and RMI)를 통해서 동적으로 로딩할 수 있도록 지원해준다.

이 Class Loader는 기술적으로 몇가지 특징을 가지고 있는데 그 내용을 살펴보면 다음과 같다.

- Hierarchical
: Class Loader는 Hierarchical 하게 생성이 가능하다. Parent class loader에서, child class loader를 갖는것과 같이 Class Loader간의 계층형 구조를 갖게 되며, 최상위의 Class Loader는 “bootstrap” Class Loader가 위치하게 된다.

- Delegate load request
: 위와 같이 Class Loader가 계층형 구조를 가지고 있기 때문에, Class 로딩상에 몇가지 규칙이 필요한데, 일정 시점에 Class Loading 요청을 받았을때, 상위 Class Loader가 Loading한 Class가 그 우선권을 가진다.
예를 들어 설명하면, Class Loader가 parent부터, CL1-CL2-CL3 순서로 생성되어 있다고 가정하자, 애플리케이션이 Class Loader CL3로 Class를 요청하면, CL3는 그 요청을 CL2로, CL2는 CL1으로 요청을 전달한다. 즉, Class 로딩의 우선 순위는 parent class가 가지고 있고, 만약에 요청받은 Class가 없을 경우에만 아래 레벌 Class Loader가 Class를 로딩하게 된다.

- Have visibility constraint
: 상위 Class Loader를 먼저 참조하는것에 이어서, Class Loader는 일종의 scope rule을 제공하는데, Child Class Loader는 Parent Class Loader의 Class를 Delegation load request를 이용하여 찾을 수 있지만, 그 반대로 Parent가 Child가 Loading한 Class를 사용할 수 는 없다. 또한 Parent의 같은 Level의 Child Class Loader는 서로 로딩한 Class를 사용할 수 없게 되어 있다.

- Cannot unload classes
: Class Loader에 의해서 Loading된 Class들은, unload될 수 없다.. Class Loader에는 Class Unloading기능이 없다. 그래서 이 unloading 기능을 우회적으로 구현하는 방법은 Class를 로드한 Class Loader 자체를 삭제하고, 새로운 Class Loader를 만들어서 다시Class 를 로드하면, reload되는 것처럼 작동하는것이 된다.

내용이 좀 어려울 수 도 있겠지만, WLS의 뒤에 나올Class Loader의 내용을 읽어보면 이해가 될것이다. Deploy 개념을 이해하는데 중요한 내용이니 이해하도록 하자.



JVM Class Loader

먼저 JVM이 가동될때, Loading되는 Class Loader는 parent부터 순서대로, Bootstrap, Extensions, System Class Loader가 올라가게 된다. 그 내용을 살펴보자

- Bootstrap Class Loader
: JVM이 실행될때 맨 처음 실행되는 Class Loader로, 가장 기본적인 JAVA실행에 필요한 가장 기본적인 Class들을 (rt.jar, i18n.jar 와 같은 기본적인 Archieve) 로딩한다.

- Extensions Class Loader
: BootStrap Loading후, 기본적으로 Loading되는 Class로 $JAVA_HOME/lib/ext에 있는 Class들이 Loading된다. 이 Class들은 별도로 classpath에 잡혀 있지 않아도 Loading된다.

- System Class Loader
: 다음으로, CLASSPATH에 정의되거나 JVM option에서 -cp, -classpath에 지정된 Class들이 로딩된다.




* JVM Class Loader


먼저 JVM이 가동될때, Loading되는 Class Loader는 parent부터 순서대로, Bootstrap, Extensions, System Class Loader가 올라가게 된다. 그 내용을 살펴보자

1. Bootstrap Class Loader : JVM이 실행될때 맨 처음 실행되는 Class Loader로, 가장 기본적인 JAVA실행에 필요한 가장 기본적인 Class들을 (rt.jar, i18n.jar 와 같은 기본적인 Archieve) 로딩한다.

2. Extensions Class Loader : BootStrap Loading후, 기본적으로 Loading되는 Class로 $JAVA_HOME/lib/ext에 있는 Class들이 Loading된다. 이 Class들은 별도로 classpath에 잡혀 있지 않아도 Loading된다.

3. System Class Loader : 다음으로, CLASSPATH에 정의되거나 JVM option에서 ?cp, -classpath에 지정된 Class들이 로딩된다.





클 래스 로더(Class Loader)는 바이트코드(bytecode)를 읽어들여 class 객체를 생성하는 역할을 한다. java.lang.ClassLoader 클래스는 추상 클래스이다. 시스템 클래스 로더(System Class Loader)라는게 있는데 요놈은 로컬 파일 시스템의 클래스 파일만을 로딩한다. 그리고 플랫폼 의존적이다.

프로그램 시작시 JVM은 시스템 클래스 로더를 이용하여 로컬 파일 시스템에서 클래스 파일을 로딩한다. 이 때 CLASSPATH 환경변수를 참조한다.

ClassLoader 클래스가 추상 클래스이기 때문에 클래스 로더는 재정의 가능하며, 클래스 로더끼리는 위임 모델(delegation model)을 활용한다. 위임 모델에는 parent class loader가 있고, 위임 모델의 chain of responsibility의 끝에는 시스템 클래스 로더가 위치해 있다.

클래스 로더가 클래스 파일을 불러들여 class 객체를 생성하는 과정은 loadClass() 메서드의 책임이며, 그 과정은 다음과 같다.
1. findLoadedClass() 메서드가 이미 로딩된 클래스인지 확인한다.
2. 1번 과정에서 찾지 못할 경우 parent class loader의 loadClass() 메서드를 호출한다.
3. 1,2번 과정에서도 찾지 못할 경우, findClass() 메서드를 호출하여 클래스를 찾은 다음 바이트코드를 읽어들여 defineClass() 메서드를 이용하여 class 객체를 생성한다.
4. 3번 과정이 실패하면 ClassNotFoundException을 던진다.


defineClass() 메서드를 이용하여 클래스를 생성하는 클래스 로더를 해당 클래스의 defining loader라고 한다. Class 클래스에 정의된 getClassLoader()를 이용하면 defining class loader의 참조를 획득할 수 있다. 또한 loadClass 과정에 참여하는 class loader를 initiating loader라고 한다.

ClassLoader에는 다음과 같은 메서드가 포함되어 있다.
ClassLoader getParent()
ClassLoader getSystemClassLoader()
Class findClass(String name)
Class loadClass(String name)
Class defineClass(String name, byte[] b, int off, int len)
Class findLoadedClass(String name)



시 스템 클래스 로더는 기동시 class path를 캐시해 두는데, 개발자가 System.setProperty() 메서드를 이용한다고 해서 시스템 클래스 로더의 행위를 변경할 수는 없다. 즉, 런타임시의 class path 정보는 시스템 클래스에 아무런 영향을 주지 못한다. 다음 SimpleClassLoader가 이러한 시스템 클래스 로더의 대안으로서 활용가능하다.

package simpleclassloader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class SimpleClassLoader extends ClassLoader {

String[] dirs;

public SimpleClassLoader(String path) {
dirs = path.split(System.getProperty("path.separator"));
}

public SimpleClassLoader(String path, ClassLoader parent) {
super(parent);
dirs = path.split(System.getProperty("path.separator"));
}

public void extendClassPath(String path) {
String[] exDirs = path.split(System.getenv("path.separator"));
String[] newDirs = new String[dirs.length + exDirs.length];
System.arraycopy(dirs, 0, newDirs, 0, dirs.length);
System.arraycopy(exDirs, 0, newDirs, dirs.length, exDirs.length);
dirs = newDirs;
}

public synchronized Class findClass(String name) throws ClassNotFoundException {
for (int i = 0; i < dirs.length; i++) {
byte[] buf = getClassData(dirs[i], name);
if ( buf != null )
return defineClass(name, buf, 0, buf.length);
}
throw new ClassNotFoundException();
}

private byte[] getClassData(String directory, String name) {
String classFile = directory + "/" + name.replace('.','/') + ".class";

int classSize = (new Long(new File(classFile).length())).intValue();
byte[] buf = new byte[classSize];
try {
FileInputStream fileIn = new FileInputStream(classFile);
classSize = fileIn.read(buf);
fileIn.close();
} catch (FileNotFoundException e) {
return null;
} catch (IOException e) {
return null;
}
return buf;
}
}


SimpleClass 로더는 프로그램이 시작된 후에도 동적으로 주어진 디렉터리로부터 클래스 파일을 로딩해 올 수 있다.




자바가상머신(JVM, Java Virtual Machine) -->

자바가상머신은 자바로 작성된 프로그램이 어떤 환경에서든지 작동할 수 있도록 해 준다. 다음 그림은 자바 가상머신의 구조이다.


전반적으로 살펴보면 다음과 같다.

클래스로더는 자바 소스를 컴파일해서 생성된 클래스 파일을 로딩한다.

클래스 파일내의 메서드, 변수들, 객체 변수들을 자바가상머신의 각 메모리에 로딩한다.

메서드 --> 메서드영역에 로딩
변수들은 --> 스택 영역에..
객체변수, 클래스변수 --> 힙 영역..

실행엔진은 메모리에 로딩된 메서드들을 실행한다.

네이티브 메서드는 자바 언어 말고 다른 언어로 된 메서드를 호출해서 수행하는 메서드이다. 이러한 메서드도 자바가상머신에서 처리한다.

자바가상머신은 위의 같은 구조로 어떤 환경이든지 자바로 만든 프로그램이라면 실행시켜주는데 가상적인 하드웨어에 가깝다.




JVM은 Java와 Java2 플랫폼의 주출돌이다.

JVM은 추상 컴퓨터 머신으로서, 실제 컴퓨터와 유사하다.

JVM은 명령어 셋과 런타임중 다양한 메모리 공간 조작을 할 수 있다.

첫번째 프로토타입 JVM은 선사에서 완성 시켯다.



jvm은 자바프로그래밍언어에 대하여 알지 못한다. 단지 바이너리 포맷많은 인식할수있다(class format의)

class format file A는 jvm 명령(또는 바이트코드)와 심볼 테이블, 및 부수 정보를 포함한다



자바 가상 머신이란 무엇인가?

Tim Lindholm과 Frank Yellin이 쓴 "자바 가상 머신 명세서( The Java Virtual Machine Specification"를 보면 자바 가상머신에 대하여 다음과 같이 정의 되어 있다.

- 명령어들의 집합과 각 명령어의 의미의 정의 : Bytecode
- 클래스 파일 형식이라고 불리는 바이너리 형식 : 플랫폼 독립적으로 동작 가능
- 프로그램에 문제가 없는지를 확인하는 알고리즘 : Verification 알고리즘


1. 명령어 집합
JVM에서 실행되는 프로그램은 Bytecode라고 불리는 명령어로 표현된다. 이런 명령어 집합은 스택 기반의 명령어와 툭수한 객체지향 명령어들로 이루어져있다.

2. 클래스 파일 형식
JVM 에서는 class에 대한 이진 파일 형식이 정의되어 있다. 이 형식은 바이트의 스트림으로 표현되며, 자바 플랫폼은 이런 바이트 스트림으로 표현된 클래스 파일을 JVM에서 사용되는 클래스로 바꾸는 방법을 제공한다. 이 방법이 바로 우리가 흔히 알고 있는 ClassLoader이다.

* 클래스 파일 형식 이라고 해서 클래스가 파일로만 존재하는것은 아니다.

3. 검증 ( Verification )
JVM은 모든 클래스를 체크해주는 알고리즘을 가지고 있다. 이런 검증 알고리즘은 프로그램이 JVM에서 요구하는 규칙들을 만족시키는지 확인하며, 프로그램이 시스템에 위험한 작업이 수행되지 않도록 보장한다.

검증 알고리즘은 다음과 같은 항목들을 검사한다.
- 구조적 관점에서 명확한 클래스 파일인지
- 모든 상수들이 정확하게 참조되는지
- 명령어들이 모두 유효한지
- 스택과 지역 변수가 적절한 타입의 값을 가지는지
- 참조하는 클래스들이 존재하며, 필요한 메소드나 필드가 모두 있는지





















3 The Structure of the Java Virtual Machine

이 책은 추상머신에 관란 명세서이다.

JVM의 구현에 관한 책이 아니다.



3.1 The class File Format

JVM에 수행 가능한 컴파일된 코드는 독립적인 바이너리 포맷이다. (OS에 독립적인)

3.2 Data Types

3.3 Primitive Types and Values 3.3.1 Integral Types and Values

3.3.2 Floating-Point Types, Value Sets, and Values

3.3.3 The returnAddress Type and Values

3.3.4 The boolean Type

3.4 Reference Types and Values

참 조 형식에는 세 종류 :. 클래스 유형, 배열 유형 및 인터페이스 휴형등 세가지 종류가있습니다 자신의 value를 동적으로 만들어 클래스 인스턴스, 배열, 또는 클래스 인스턴스의 배열을 참조하거나, 각각 인터페이스를 구현하는 것입니다. 참조 value도 특별 null 참조는 여기에 계열로 표시되며 개체에 대한 참조가 될 수있습니다. 이 null 참조 처음은 아니지만 런타임 유형이 어떤 형식으로 캐스팅 될 수있습니다



3.5 Runtime Data Areas

the pc register(바이트 코드 명령어의 주소, 쓰레드당 하나의 PC, 쓰레드가 어떤 명령으로 실행할지에 대해 기록하는 영역) : PC Registers는 각 JVM 스레드에 존재하는데 ,JVM 스레드가 시작할때 생성되고, JVM에서 현재 실행할 명령(instruction)의 주소를 나타내고 있다 . 자바가상머신당 하나의 PC Registers가 존재한다. (수행중이던 명령어의 주소를 가진다)

jvm stacks(쓰레드 당 하나의 자바 스택, 메소드 프레임을 위한 기억 공간, 지역변수, 지역객체 레퍼런스, 메소드 파라미터, 메소드 리턴값) :

Java Stack은 각 스레드가 생성되는 것과 동시에 생성되며 , 각 스레드 에서 서로 독 립적인 Java Stack을 유지한다 . 각 스레드를 위한 Java Stack에서는 현재 실행하고 있는 각 메소드를 위한 Stack Frame을 포함하고 있다. 스레드가 어떤 메소드를 호출 하면 해당 메소드를 위한 Stack Frame을 해당 스레드의 JavaStack에 푸시(push)하 고, 호출한 메소드의 수행이 끝나면 해당 메소드를 위한 StackFrame을 스레드의 Java Stack으로 부터 팝(pop)하게 된다. 메소드내에 선언되어 있는지역 변 수와 리턴 결 과를 저장하기 위해 사용된다고 할 수 있다.

-> StackOverflowError(허용된 범위 보다 큰 공간을 쓰레드가 요구할때), OutOfMemoryError







heap(객체와 배열을 윟나 기억 공간, GC의 대상, 모든 쓰레드가 공유함) : Heap은 자바 가상 머신에서 실행되고 있는 모든 스레드에 의해 공유되기 때문에 ,Heap을 사용하려는 스레드간의 적절한 동기화(synchronization) 작업이 필요하다. 자바 가상 머신을 실행 할 때 “-ms32m”, “-mx64m” 등과 같은 옵션을 이용하여 Heap의 최소/최대 크기를 지정해 줄 수 있다.

모든 클래스 인스턴스와 배열이 배치된다. 힙은 자동 스토리지 관리 시스템(GC)의 관리 대상이다

-> OutOfMemoryError



method area(적재된 모든 클래스에 대한 모든 정보가 저장된다. 모든 쓰레드가 공유, Runtime Constant pool+클래스 생성자와 메소드 코드 저장소) : Mehod Area는 자바 가상 머신에서 실행 되고 있는 모든 스레드에 의해 공유된다.자바 가상 머신이 시작될때 생성되며 ,Mehod Area를 사용하려는 스레드간의적절한 동기화(synchronization) 작업이 필요하다.



runtime constant pool (클래스 인스턴스 변수, 인스턴스 레퍼런스, static 변수, static 인스턴스 레퍼런스, jvm의 모든 쓰레드들이 공유하는 영역): 클래스의 심볼 테이블로 메소드 영역에 할당, 동적 연견의 핵심



native method stacks (네이티브 메소드에서 사영되는 값 저장ive Method Stack은 각 스레드당 하나씩 생성된다. 스레드가 네이티브메소드(Native Method)를 호출하면 Java Stack을 벗어나게 되며,이때 네이티브 메소드에 의해 Native Method Stack이 사용된다 . 네이티브 메소드에서 자바 메소드를 다시 호출하게 되면 , Java Stack으로 되돌아가게 된다.





*Native Method : C, C++같은 언어로 구현된 메소드, 주로 하드웨어에 대한 접근 용 메소드임 (JNI - 자바 시스템과 네이티브 메소드 사이의 표준 인터페이스)



vm 모든 쓰레드가 공유하는 영역은 runtime constant pool, method area, heap 이

다.







3.6 Frames

프레임은 데이터와 연산 도중의 부분적인 결과를 저장하는데 사용된다.

-메소드의 결과과 반환

-예외 사항 디스패치

-동적 링킹



생성 시점 : 자바 메소드가 호출될때마다 쓰레드의 자바 스택에 생성된다. 이때 현재 수행중인 메소드에 해당하는 프레임을 현재 프레임, 그 메소드를 현재 메소드, 그리고 현재 메소드가 속한 클래스를 현재 클래스라고 부른다

유지정보 : 지역 변수와 피연산자 스택 정보를 지니고 있다



3.6.1 Local Variables

자바 프레임은 지역 변수를 하나의 배열로 저장하고 있다.





3.6.2 Operand Stacks

피연산자 스택

자바 가상 머신의 명령어에 사용될 피연산자 값들에 사용된다.

메소드에 인자를 전달하고 결과값을 되돌려 받는 데에 사용된다



pop1->pop2->1+2->push3



3.6.3 Dynamic Linking

동적 링킹 프레임은 현재 메소드의 타입에 대한 정보를 담은 상수 풀의 엔트리에 대한 레퍼런스를 포함하고 있다

과정

-메소드를 위한 클래스 파일 내부의 코드는 수행될 메소드와 그에 전달될 변수들에 대한 참조이지만, 그것은 메모리상의 위치가 정해지지 않은 심볼릭 레퍼런스이다.

-적 링킹은 이 심볼릭 메소드 레퍼런스를 구체적인 메소드 레퍼런스로 변환 시킨다



3.6.4 Normal Method Invocation Completion

정상적인 메소드 수행완료

-예외사항이 없이 결과값이 되돌아가는 상태를 말한다.

할일

-이제 메소드를 호출하기 이전의 상태로 복구해야 한다. 이때 프레임이 사용된다.

복구 후 프로그램 카운터를 하나 증가 시킨다. 복구된 시점에는 메소드를 호출하는 인스트럭션에 카운터가 위치하고 있을 것이다.

이제 프레임의 피연산자 스택으로부터의 결과값을 이용하여 수행을 속개한다.



3.6.5 Abrupt Method Invocation Completion

예외 사항이 발생한 경우로 결과값은 존재하지 않는다.

예회 사항을 처리하는 루틴이 존재하는 곳까지 예외사항을 던져 나간다

3.6.6 Additional Information

디버깅 정보와 같은 추가적인 정보가 프레임에 포함되게 할 있다.





3.7 Representation of Objects 객체의 표현

- 객체에 대한 내부적인 특징 표현은 없다

클래스 인스턴스에 레퍼런스

- 객체의 메소드들을 포함하는 테이블에 대한 포인터

- 객체의 타입을 나타내는 Class 객체에 대한 포인터

- 객체의 데이터가 할당된 힙의 영역에 대한 포인터



3.8 Floating-Point Arithmetic 3.8.1 Java Virtual Machine Floating-Point Arithmetic and IEEE 754

3.8.2 Floating-Point Modes

3.8.3 Value Set Conversion

3.9 Specially Named Initialization Methods

3.10 Exceptions

3.11 Instruction Ser Summary

인스트럭션 세트의 요약

-opcode는 1바이트로 제한한다. 그리고 그 뒤로 0개 이상의 피연산자가 올수 있다

하지만 이러한 제약은 성능을 향상 시킬 있는 구현 기법을 사전에 봉쇄한다.

그리고 인스트럭션의 숫자도 제한된다.



4 The class File Format

4.1 The ClassFile Structure

4.2 The Internal Form of Fully Qualified Class and Interface Names

4.3 Descriptors 4.3.1 Grammar Notation

4.3.2 Field Descriptors

4.3.3 Method Descriptors

4.4 The Constant Pool 4.4.1 The CONSTANT_Class_info Structure

4.4.2 The CONSTANT_Fieldref_info, CONSTANT_Methodref_info, and CONSTANT_InterfaceMethodref_info Structures

4.4.3 The CONSTANT_String_info Structure

4.4.4 The CONSTANT_Integer_info and CONSTANT_Float_info Structures

4.4.5 The CONSTANT_Long_info and CONSTANT_Double_info Structures

4.4.6 The CONSTANT_NameAndType_info Structure

4.4.7 The CONSTANT_Utf8_info Structure

4.5 Fields

4.6 Methods

4.7 Attributes 4.7.1 Defining and Naming New Attributes

4.7.2 The ConstantValue Attribute

4.7.3 The Code Attribute

4.7.4 The Exceptions Attribute

4.7.5 The InnerClasses Attribute

4.7.6 The Synthetic Attribute

4.7.7 The SourceFile Attribute

4.7.8 The LineNumberTable Attribute

4.7.9 The LocalVariableTable Attribute

4.7.10 The Deprecated Attribute

4.8 Constraints on Java Virtual Machine Code 4.8.1 Static Constraints

4.8.2 Structural Constraints

4.9 Verification of class Files 4.9.1 The Verification Process

4.9.2 The Bytecode Verifier

4.9.3 Values of Types long and double

4.9.4 Instance Initialization Methods and Newly Created Objects

4.9.5 Exception Handlers

4.9.6 Exceptions and finally

4.10 Limitations of the Java Virtual Machine

5 Loading, Linking, and Initializing 5.1 The Runtime Constant Pool

5.2 Virtual Machine Start-up

5.3 Creation and Loading 5.3.1 Loading Using the Bootstrap Class Loader

5.3.2 Loading Using a User-defined Class Loader

5.3.3 Creating Array Classes

5.3.4 Loading Constraints

5.3.5 Deriving a Class from a class File Representation

5.4 Linking 5.4.1 Verification

5.4.2 Preparation

5.4.3 Resolution

5.4.4 Access Control

5.5 Initialization

5.6 Binding Native Method Implementations













6 The Java Virtual Machine Instruction Set

6.1 Assumptions: The Meaning of "Must"

6.2 Reserved Opcodes

6.3 Virtual Machine Errors

6.4 Format of Instruction Descriptions

7 Compiling for the Java Virtual Machine 7.1 Format of Examples

7.2 Use of Constants, Local Variables, and Control Constructs

7.3 Arithmetic

7.4 Accessing the Runtime Constant Pool

7.5 More Control Examples

7.6 Receiving Arguments

7.7 Invoking Methods

7.8 Working with Class Instances

7.9 Arrays

7.10 Compiling Switches

7.11 Operations on the Operand Stack

7.12 Throwing and Handling Exceptions

7.13 Compiling finally

7.14 Synchronization

7.15 Compiling Nested Classes and Interfaces

8 Threads and Locks 8.1 Terminology and Framework

8.2 Execution Order and Consistency

8.3 Rules About Variables

8.4 Nonatomic Treatment of double and long Variables

8.5 Rules About Locks

8.6 Rules About the Interaction of Locks and Variables

8.7 Rules for volatile Variables

8.8 Prescient Store Operations

8.9 Discussion

8.10 Example: Possible Swap

8.11 Example: Out-of-Order Writes

8.12 Threads

8.13 Locks and Synchronization

8.14 Wait Sets and Notification

9 Opcode Mnemonics by Opcode







Java Memory Manager

자바는 new 키워드를 통해 메모리 할당을 요청한다. 자바는 c, c++의 free, delete와 같은 키워드를 제공하지 않는다. (프로그래머가 당당된 메모리를 해제하는 키워드를 제공하지 않는다)

이는 가상 머신 내부의 메모리 관리 서브 루틴, 즉 가지비 컬렉터가 이러한 처리를 자동적으로 담당하기 떄문이다.

가비지 컬렉터는 수행중인 프로그램에 할당된 메모리 여역들 중에서 더 이상 사용되지 않을 것으로 판단되는 객체들이 차지하고 있는 메모리 영역을 추적하여, 해당 메모리 영역을 재사용 할 수 있도록 반환하는 처리 루틴을 말한다.







Java Virtual Machine Execution

자바 프로그램이 메모리에 로딩되고 실행되기 까지의 과정

1. 자바 머신 구동

2. 클래스나 인터페이스를 찾아 로딩

3. 클래스 파일의 포맷을 검사(verification->preparation->resolution->검사 완료)

4. 정적 또는 동적 방법으로 클래스 변수 참조들의 메모리 주소를 결정하는 등 배치

링킹 과정 실시

5. 클래스 인스턴스 생성

5. 메인 메소드 실행



Start Up VM -> Class and Interface Type Loading on local File System

-> Linking -> Initialization -> Procedures for creation of new Class Instances



예를 들어 JVM의 수행 과정을 살펴보자.

1. c:> java MyProgram a b c (와 같은 명령을 주었다고 하자)



2. 클래스 적재

- 1의 명령이 내려졋다면 자바 가상머신의 한 인스턴스는 이 클래스(MyProgram.class)를 찾기 시작한다.

- 클래스는 디폴트 경로나 CLASSPATH를 통해서 검색되며, 발견 이후로는 CLASSLOADER에 의해 가상 머신에 적재된다



3. 링킹

클래스와 클래스가 필요로 하는 모든 클래스 또는 인터페이스를 메모리 상에서 조립하는 과정을 진행한다. 조깁 과정은 다음 세 부분으로 생각할 수 있다.

- verification : 클래스가 정해진 포맷에 맞게 작성된 것인지를 확인한다. 클래스의 모든 형식은 글래스 파일 타입에 맞아야 하고, 현재 가상 머신의 요구를 만족 시킬수 있어야 한다.

- preparation : 여기서는 정적인 메모리 바인딩이 이루어진다.

- resolution : 이 단계는 링킹에 있어 옵션이라 할수 있다. 이것을 구현에 따라 로딩 이전의 전 단계에서 미리 행할 수도 있다. 하지만, 이것은 후의 단계에서 에러를 유발 시킬 가능성이 높다 만일 MyProgram이 다른 클래스에 대한 참조를 많이 가지고 있다 할지라도, 실행 도중 사용되지 않는다면 여기에 대해 resolution이 행해지지 않을 것 이다(checking symbolic reference form MyProgram to other classes and interfaces)



4. 클래스에 대한 초기화 작업

- 수퍼 클래스에 대한 초기화를 일단 수행한다.

- 클래스 변수들의 초기화를 수행한다.



5. 메인 메소드가 수행된다





이제 각 부분들이 어떤 프로세스를 거치는지 좀 더 디테일하게 따져보도록하자.

<0.Start-up>

<1.로딩-적재>

주어진 클래스 이름에 따라 클래스나 인터페이스의 이진 폼을 찾아내는것

ClassLoader

-디폴트 클래스 적재기

1. 로딩 속도를 높이는 방안

- 한번 적재한 클래스나 인터페이스의 이진 내용을 캐쉬한다

이럴 경우, 새로이 내용이 변경된 클래스에 대한 변경 내용 반영이 문제가 될것이다



2. 한번에 필요한 클래스를 그룹단위로



발생할수 있는 에러의 종류

ClassFormatError : 클래스 파일의 포맷이 표준과 맞지 않을 경우

ClassCircularityError : 환형 관계가 성립되어 버린 경우 (클래스의 초기화시에 루프가 발견될 경우)

NoClassDefFoundError : 클래스 로더가 주어진 이름의 클래스나 인터페이스를 발견하지 못했을때

UnsupportedClassVersionError : 현재 구동되는 JVM에서 지원되지 않는 Version의 class 파일이 로드될 경우 발생



<2.링킹>



클래스나 인터페이스 이진 파일을 자바 가상 머신상에서 실행 가능한 상태로 만들게 되는 과정

이 과정이 실제로는 언제 일어나느냐에 관해서는 사실 유연성있게 구성하면 된다.

미리 필요한 클래스나 인터페이스를 모두 적재해 메모리 상의 위치 관계를 결정지을 수도 있는 반면(static), 그 클래스나 인터페이스가 사용되기 전까지는 링킹이 안되게 할수도 있다(lazy)

1. verification

클래스 파일이나 인터페이스 파일의 이진 형식을 검사한다.

여기서 검사하게 되는 것은 다음과 같다.

- whether every instruction has a valid operation code : 유효한 operation code인가?

- whether every branch instruction branches to the start of some other instruction



- whether every method is provided with a structurally correct signature



- whether every instruction obeys the type discipline of the Java language

모든 명령어가 자바 언어의 타입 규율을 혹 어기지 않았는지

이 과정중에 에러가 발생하게 되면, VerifyError 예외 사항이 발생하게 된다



2. preparation

이 과정에서는 클래스나 인터페이스의 정적 필드의 위치가 지정된다 그리고 이들 값은 자바 표준에 정해진 디폴트 값으로 초기화 된다.

하지만, 구별해야 할 것은 이 과정이 비록 변수의 값 초기화와 관련있다 할 지라도, 이 자체가 명시적인 생성자의 수행결과는 아니다. 그것은 initialization에서 수행될것이다.

또한 메소드 테이블과 같은 여러 메소드를 위한 자료구조도 이때 형성되는데, 이것은 메소드 수행시 계승 계층을 따라 메소드를 검색하는 작업을 절약해준다.

- AbstractMethodError : A class not declared to be abstract has an abstract method

추상 클래스가 아닌데, 추상 메소드를 가질때



3. resolution

자바 바이너리 파일은 다른 클래스나 인터페이스의 필드, 메소드에 대해 Fully Qualified Name으로 접근한다. 필드나 메소드가 속한 클래스나 인터페이스의 이름을 사용한 접근법이다

IllegalAccessError : 필드에 접근할 수 없는 에러 - 필드가 private, protected, 나 default access (not public)로 선언되어 있을 때, 그리고 클래스가 Public으로 선언되어 있지 않을 때 -> 이것은 처음에는 Public으로 선언되어 있어 문제없이 컴파일되었으나, 후에 그 클래스 파일이 수정되었을 때 발생할 수 있다.

InstantiationError : 참조하는 클래스가 추상 클래스가 아니던 것이 추상 클래스로 변경되었을 때

NoSuchFieldError : 존재했던 필드가 삭제, 변경되었을 때

NoSuchMethodError : 존재했던 메쏘드가 삭제,변경되었을 때



























링킹 작업이 끝나면 다음은 생성자 수행등의 초기화 작업이다.

1. 클래스 초기화

- 정적 변수 초기화

- 클래스 초기화에서는 반드시 상위 클래스 초기화를 먼저 거쳐야 한다.

- 클래스에 의해 구현된 인터페이스의 경우 초기화 과정을 거칠 필요없음



2. 인터페이스 초기화

- 인터페이스에 선언된 필드의 초기화를 수행한다.

- 인터페이스의 상위 인터페이스는 이때 따로 초기화 과정을 거칠 필요가 없다



클래스나 인터페이스의 초기화 과정을 진행하게 되는 것은 능동적 사용이 되는 경우이다.

(능동적 사용이란 자신의 메소드 수행 요청시, 클래스의 생성자 호출시, 클래스 내 상수가 아닌 필드가 사용되거나 값을 할당 받을 때)



다시 말해 필드는 자신을 선언한 클래스나 인터페이스에 대해서만 능동적 사용이 되는 것이고, 그렇지 않은 경우에는 모두 수동적 사용이 되는 것이다



Initial단계를 구체적으로 살펴보자

1. Class 객체를 통기화 한다. 즉, 이에 대한 락을 획득한다.

2. 만일 다른 쓰레드에 의해 초기화 작업이 진행중에 있다면, 그 쓰레드가 Class객체에 대해 락을 해제 할 때까지 기다리면서 잠시 중단 상태에 돌입힌다. 이때 자신이 얻었던 락도 일시적으로 해제 시킨다. 다시 쓰레드가 동기화 메커니즘에 의해 깨어날 때 작업은 속재 된다.

3. 만일 지금 초기화 작업을 진행중인 쓰레드가 다름 아닌 현재 쓰레드라면 필시 재귀적인 초기화작업이 분명하므로 더 이상의 새로운 초기화 작업은 하지 않고, 락을 해제한 후 복귀한다.



4. 이미 초기화 작업이 마쳐진 상태라고 해도 마찬가지로 락을 풀고 초기화를 정상적으로 종료 한다.



5. Class객체가 erroneous한 상태라면, 클래스 초기화에 문제가 발생한 것으로, 더 이상 작업을 진행할 수 없다. 락을 해제한 후 No ClassDefFoundError 예외 사항을 발생 시킨다.



6. 이 단계까지 왔다면, 이제 이 쓰레드가 본격적으로 초기화 작업에 돌입하도록 허가를 받은 것이므로, 현재 초기화가 진행중임을 표시하고, Class에 대한 락을 해제 한다.



7. 클래스 객체가 인터페이스가 아닌 클래스를 나타낸다면, 우선 수퍼 클래스가 있는지 확인 한다. 만일 존재하면 그것에 대해 재귀적으로 이 스탭을 밟되 필요에 따라 Verification, Preparation도 행한다. 만일 슈퍼클래스에서 에러가 발생해 예외 사항이 날아 온다면, 즉시 클래스 객체에 락을 걸고 에러가 있음을 표시한다. 그리고 모든 쓰레드들에 알린 후 자신도 같은 예외 사항을 던지며 수행을 끝낸다.



8. 클래스 변수들의 초기화 작업이나, final변수에 대한 초기화를 코드에 등장하는 순서대로 행한다.

final static변수들은 컴파일 타임에 초기화 되어 있다



9. 앞선 초기화 작접들이 문제없이 종료 되었다면, 다시 Class객체에 락을 걸고 모든 초기화가 완료되었다는 표시를 한다. 그리고, 현재 가지고 있는 락을 풀면서 모든 대기 상태의 클래스 들에게 이 사실을 통보 한다



10. 그렇지 않고, E예외 사항을 던지면서 비정상적으로 종료 상태이고, 그 예외 사항이 Error클래스나 그 서브 클래스가 아니라면, ExceptionInitializationError클래스의 새로운 인스턴스를 E를 인자로 하여 생성해 이를 다음번 단계에서 사용한다.



11. Class객체에 락을 열고 errorneous상태를 기록하고, 모든 락을 해체한 후 정료한다













클래스의 새로운 인스턴스가 생성되는 경우는 명시적으로 생성되는 경우도 잇겠지만 암시적으로 생성되는 경우도 있다.



1. 명시적 생성

- 클래스 인스턴스의 생성을 지시하는 자바 문장을 만낫을때 (new)

-Class에 속한 newinstance 메소드가 호출되었을때(newinstance)



2. 암시적 생성

- 문자열을 포함하는 클래스나 인터페이스를 로딩하는 경우 String객체를 암시적으로 생성한다.

- 문자열 두개를 연결하는 연산자를 수행할때





새로운 인스턴스를 생성하는 대략적인 과정은 다음과 같다.

1. 메모리 공간이 할당된다. 이 클래스나 상위 클래스에 선언되어 있는 인스턴스 변수에 대한 공간을 할당한다. 이 변수들은 자바에 정해져 있는 대로 초기값을 정하게 된다.

2. 클래스의 생성자가 수행된다.

3. 생성자의 수행이 끝난 후, 새로이 생성된 객체의 참조를 변환한다



생성자가 수행되는 단계에 대하여 자세히 알아보자.

1. 생성자에 들어갈 인자들을 할당한다.

2. 클래스 내의 생성자는 여러개가 있을수 있다. 이중 다른 생성자를 도중에 호출하는 생성자가 있을수도 있다. 이 경우에는 여기서 보개될 5단계의 과정을 재귀적으로 계속 부르게 되며, 이상없이 끝난하면 5단꼐를 진행한다.

3. 수퍼 클래스의 생성자를 호출하는 문장이 있으면, 수퍼 클래스의 생성자를 수행하는 단꼐를 먼저 수행한다.

4. 인스턴스 변수 초기화를 수행한다. 변수들은 소스 코드에 등장하는 순서대로 처리된다.

5. 생성자의 나머지 부분을 처리 한다.

참고로, 하위 클래스가 오버라이드한 메소드를 그 하위 클래스의 객체 생성시 생성작업이 채 완료되기 전에 오출된다면, 그래도 오버라이드된 메소드가 호출된다.







Object 클래스에 정의된 finalize메소드는 객체가 가비지 수집되기 직전에 호출된다.

이는 주로 그 객체가 사용하고 있던 리소스들을 반환하는데 사용된다.

(명시적으로도 호출이 가능하다)





가상 머신이 종료되는 시점은 다음과 같다.

1. 모든 쓰레드가 종료 되었을때

2. 쓰레드가 Runtime클래스나 System클래스의 exit()메소드를 호출하였을때.

하지만 더욱 중요한 것은 이러한 것은 모두 권한을 지닌 쓰레드만이 가능하다는것이다.

TOTAL 19,751 TODAY 3