인스턴스와힙메모리

임준철·2021년 4월 11일
0

OOP

목록 보기
3/6

인스턴스와힙메모리

인스턴스란

  • 클래스로부터 생성된 객체
  • 힙 메모리에 멤버 변수의 크기에 따라 메모리가 생성
  • 클래스를 기반으로 new 키워드를 이용하여 여러 개의 인스턴스를 생성

  • 참조변수와 참조 값
    • ch05.classPart.Student@1ddc4ec2의 주소값은 실제 물리적인 주소값은 아니고
      가상 jvm이 준 해시코드 값이다. student가 가리키는 메모리의 위치가 32비트를 나타내는 메모리를 가리킨다
Student student  = new Student();
System.out.println(student);

  • 문자열(String) - 한번 만든 문자열은 변하지 않는다. (Immutable) 그래서 새로운 문자열을 만들어서 값을 넣어 주는 것과 같다.

  • 클래스는 문자열과 달리 mutable 변할 수 있다.

  • 참조형 객체이기 때문에 new일때만 새로운 객체를 생성하고, 이렇게 하면 같은 객체를 가리킨다.

  • 이처럼 carThree 에 carOne을 넣었을 때 Three에서 속성 값을 변경시켰을 때 one의 속성값도 변경됨.

    Car carThree = carOne;
    
    System.out.println(carThree.speed); //carThree.speed = 5;
    System.out.println(carThree.speed);// 5
    System.out.println(carOne.speed);// 5

메모리 할당 시점

변수가 메모리에 생성될 때는 초기화가 이루어지는 시점인데,
초기화가 되는 시점은 클래스나 메소드에서 초기화 값을 준다고 해도 메모리에 생성이 되는게 아니다.
변수를 선언하는 것은 메모리를 자료형의 크기만큼 쓰겠다라고 하는 것이다.(메모리에 공간 확보)
변수 초기화는 메모리에 실제 값을 할당 하는 것이다.
메인 메소드안에 있는 변수들은 실행될 때 메모리에 생성됨.
정적 변수 - 클래스가 생성이 될 때 메모리에 할당이 된다.

클래스와 객체의 메모리 구조

메모리 영역

  • 클래스 영역(class area, method area, code area, static area) 클래스의 공통된 부분이 들어감 어떤 필드가 있는지 어떤 타입을 갖는다던지

  • 어떤 메소드가 있고 어떤동작을 하는 코드라던지. 프로그램이 돌아가면 계속 존재함.

    • field 정보, method 정보, type 정보, constant pool
    • ex) method의 정보라고 하면 접근 제어자와 자료형, 메소드명이 이러한 메소드가 있다, 어떤동작을 한다 라는 정보만 생성이 된다.
  • 스택 영역 메소드콜이 이뤄질때 메소드에 의해 이뤄지는 임시적인 영역

    • method 호출 시 선언된 로컬 변수(호출시 임시로 있는 공간 (사라짐))
  • 힙 영역 new키워드로 발생함.

    • new 키워드로 생성된 객체
    • garbage collection이 동작하는 영역 : 더 이상 사용하지 않는 메모리를 알아서 반환하는 jvm의 기능을 의미한다.(GC)
  • 클래스와 객체의 메모리 구조 예제

    public class MemoryStructure { // 클래스 영역
        int x, y; 
        // 힙 영역 객체에 속하기 때문에 객체를 콜할 때는 힙 영역에 들어감. 객체에 속하는 속성들이므로.
        // 클래스가 아니기 때문에 값 자체가 담긴다.(32비트 값을 잡아서 쓰여져있음)
    
        String string = "String!!"; 
        // 힙영역, 상수풀에도 생성, 애는 상수풀에 생성됨. 클래스를 만드는 클래스는 힙영역에있고 내용은 상수풀에 들어감.
    
        public void method(int value){ // 클래스 영역에 만들어 짐 (메소드의 정의)
            // int value = > 스택 영역
            char c = 'w'; // 스택 영역
        }
        // 대부분의 주소값은 64비트 운영체제가 대부분 64비트이기때문에 거기에 맞춰지는 것.
    
    }

String 타입의 메모리 구조

  • class, method 같은 것들은 클래스 영역에 만들어지고,
    method 안에 있는 값들은 스택영역에 만들어졌다가 method의 생명주기가 끝나면 사라짐.

  • class 안에 변수들은 힙영역에 생성이 되는데, 정수, 실수형 변수는 constant pool 안에 정의 되어있는 값들을 가져와서 사용하는 것이고,
    String은 정의할 때 힙 영역에 값이 생성됨.

  • 처음에 young메모리(nursery)에 생성되었다가 오랫동안 사용하면 올드메모리로 옮겨짐.

  • new로 생성했을 때 기본적으로 young 메모리에 들어간다.

    @org.junit.Test
    public void testStringEquality (){
        final String literal = "Hello";
        final String object = new String("Hello");
    
        Assert.assertTrue(literal.equals(object));
        Assert.assertFalse(literal == object);
    }
  • 위에서 String의 equals은 true, ==는 false가 나오는 경우를 볼 수 있는데,

  • equals는 문자열을 비교하고, ==는 객체의 주소값을 비교하기 때문이다.

    @org.junit.Test
    public void testStringIntern(){
        final String literal = "Hello";
        final String object = new String("Hello");
        final String intern = literal.intern();
    
        Assert.assertTrue(literal.equals(object));
        Assert.assertFalse(literal == object);
        Assert.assertTrue(literal.equals(intern));
        Assert.assertTrue(literal == intern);
    }

위의 코드를 보면 intern()메서드를 호출한 결과값을 intern 변수에 할당되는 것을 볼 수 있다.
그 후 literal과 object의 동일성(==)과 동등성(equals)를 비교해보면 둘다 true값이 나와 테스트에 성공하게 된다.
리터럴로 "Hello"라는 문자열이 string constant pool에 저장되었고,
inter() 메서드를 호출하면서 string constant pool에서 Hello라는 문자열을 검색하고
이미 존재하기 때문에 "Hello" 의 동일한 주소값을 반환하게 되어 true가 나오게 된다.

  • String을 리터럴로 선언할 경우 내부적으로 String의 intern()메서드가 호출되게 된다.
  • intern() 메서드는 주어진 문자열이 string constant pool에 존재하는지 검색하고 있다면 그 주소값을 반환 하고, 없다면 string constant pool에 넣고 새로운 주소값을 반환한다.
profile
지금, 새로운 문을 열자! 문 저편에 무엇이 있을지 두렵더라도!!

0개의 댓글