Разбиране на паметта в JVM

Както вече знаете, JVM изпълнява Java програми в себе си. Като всяка виртуална машина, тя има своя собствена система за организация на паметта.

Оформлението на вътрешната памет показва How работи вашето Java приложение. По този начин могат да се идентифицират тесните места в работата на applicationsта и алгоритмите. Нека да видим How работи.

Разбиране на паметта в JVM

важно! Оригиналният модел на Java не беше достатъчно добър, така че беше ревизиран в Java 1.5. Тази version се използва и до днес (Java 14+).

Купчина конци

Моделът на паметта на Java, използван вътрешно от JVM, разделя паметта на стекове и купчини от нишки. Нека разгледаме модела на паметта на Java, логически разделен на блокове:

Купчина конци

Всички нишки , изпълнявани в JVM, имат свой собствен стек . Стекът от своя страна съдържа информация за това кои методи е извикала нишката. Ще нарека това „стек за повиквания“. Стекът за извикване се възобновява веднага щом нишката изпълни своя code.

Стекът на нишката съдържа всички локални променливи , необходими за изпълнение на методи в стека на нишката. Една нишка има достъп само до собствения си стек. Локалните променливи не са видими за други нишки, а само за нишката, която ги е създала. В ситуация, в която две нишки изпълняват един и същ code, и двете създават свои собствени локални променливи. Така всяка нишка има своя собствена version на всяка локална променлива.

Всички локални променливи от примитивни типове ( boolean , byte , short , char , int , long , float , double ) се съхраняват изцяло в стека на нишката и не са видими за други нишки. Една нишка може да предава копие на примитивна променлива на друга нишка, но не може да споделя примитивна локална променлива.

Купчина

Купчината съдържа всички обекти, създадени във вашето приложение, независимо коя нишка е създала обекта. Това включва обвивки на примитивни типове (например Byte , Integer , Long и т.н.). Няма meaning дали обектът е създаден и присвоен на локална променлива or е създаден като членска променлива на друг обект, той се съхранява в купчината.

По-долу има диаграма, която илюстрира стека за извикване и локалните променливи (те се съхраняват в стекове), Howто и обекти (те се съхраняват в купчината):

Купчина

В случай, че локалната променлива е от примитивен тип, тя се съхранява в стека на нишката.

Локална променлива може също да бъде препратка към обект. В този случай препратката (локална променлива) се съхранява в стека на нишката, но самият обект се съхранява в купчината.

Обектът съдържа методи, тези методи съдържат локални променливи. Тези локални променливи също се съхраняват в стека на нишката, дори ако обектът, който притежава метода, се съхранява в купчината.

Членските променливи на обект се съхраняват в купчината заедно със самия обект. Това е вярно Howто когато членната променлива е от примитивен тип, така и когато е препратка към обект.

Статичните променливи на класа също се съхраняват в купчината заедно с дефиницията на класа.

Взаимодействие с обекти

Обектите в купчината могат да бъдат достъпни от всички нишки, които имат препратка към обекта. Ако една нишка има достъп до обект, тогава тя може да има достъп до променливите на обекта. Ако две нишки извикат метод на един и същи обект едновременно, и двете ще имат достъп до членските променливи на обекта, но всяка нишка ще има собствено копие на локалните променливи.

Взаимодействие с обекти (купчина)

Две нишки имат набор от локални променливи.Локална променлива 2сочи към споделен обект в купчината (Обект 3). Всяка от нишките има собствено копие на локалната променлива със собствена препратка. Техните препратки са локални променливи и следователно се съхраняват в стекове от нишки. Две различни препратки обаче сочат към един и същ обект в купчината.

Моля, имайте предвид, че генералътОбект 3има връзки къмОбект 2ИОбект 4като членски променливи (показани със стрелки). Чрез тези връзки имат достъп две нишкиОбект 2ИОбект4.

Диаграмата също показва локална променлива (локална променлива 1от methodTwo ). Всяко негово копие съдържа различни препратки, които сочат към два различни обекта (Обект 1ИОбект 5), а не същият. Теоретично и двете нишки имат достъп и до дветеОбект 1, така че даОбект 5ако имат препратки към двата обекта. Но в диаграмата по-горе всяка нишка има препратка само към един от двата обекта.

Пример за взаимодействие с обекти

Нека да видим How можем да демонстрираме работата в code:

public class MySomeRunnable implements Runnable() {

    public void run() {
        one();
    }

    public void one() {
        int localOne = 1;

        Shared localTwo = Shared.instance;

        //... do something with local variables

        two();
    }

    public void two() {
        Integer localOne = 2;

        //... do something with local variables
    }
}
public class Shared {

    // store an instance of our object in a variable

    public static final Shared instance = new Shared();

    // member variables pointing to two objects on the heap

    public Integer object2 = new Integer(22);
    public Integer object4 = new Integer(44);
}

Методът run() извиква метода one() , а one() на свой ред извиква two() .

Методът one() декларира примитивна локална променлива (localOne) от тип int и локална променлива (localTwo), което е препратка към обект.

Всяка нишка, изпълняваща метода one(), ще създаде свое собствено копиеlocalOneИlocalTwoвъв вашия стек. ПроменливиlocalOneще бъдат напълно отделени един от друг, намирайки се в стека на всяка нишка. Една нишка не може да види Howви промени прави друга нишка в нейното копиеlocalOne.

Всяка нишка, изпълняваща метода one(), също създава свое собствено копиеlocalTwo. Въпреки това, две различни копияlocalTwoв крайна сметка сочи към същия обект в купчината. Факт е, чеlocalTwoсочи към обекта, посочен от статичната променливаинстанция. Има само едно копие на статична променлива и това копие се съхранява в купчината.

Така че и двете копияlocalTwoв крайна сметка сочи към същия споделен екземпляр . Споделеният екземпляр също се съхранява в купчината. СъвпадаОбект 3в диаграмата по-горе.

Обърнете внимание, че споделеният клас също съдържа две членски променливи. Самите променливи на членовете се съхраняват в купчината заедно с обекта. Две членски променливи сочат към два други обектаЦяло число. Тези цели числа съответстват наОбект 2ИОбект 4на диаграмата.

Също така имайте предвид, че методът two() създава локална променлива с имеlocalOne. Тази локална променлива е препратка към обект от тип Integer . Методът задава връзкатаlocalOneза да посочи нов екземпляр на Integer . Връзката ще бъде съхранена в нейното копиеlocalOneза всяка нишка. Два екземпляра Integer ще бъдат съхранени в купчината и тъй като методът създава нов обект Integer всеки път, когато се изпълни, двете нишки, изпълняващи този метод, ще създадат отделни екземпляри Integer . Те съвпадатОбект 1ИОбект 5в диаграмата по-горе.

Обърнете внимание и на двете членски променливи в споделения клас от тип Integer , който е примитивен тип. Тъй като тези променливи са членски променливи, те все още се съхраняват в купчината заедно с обекта. Само локални променливи се съхраняват в стека на нишката.