Стек памет и куп пространство в Java

1. Въведение

За да стартира приложение по оптимален начин, JVM разделя паметта на стек и куп памет. Винаги, когато декларираме нови променливи и обекти, извикваме нов метод, декларираме String или изпълняваме подобни операции, JVM обозначава памет към тези операции от Stack Memory или Heap Space.

В този урок ще обсъдим тези модели памет. Ще изброим някои ключови разлики между тях, как те се съхраняват в RAM, функциите, които предлагат, и къде да ги използваме.

2. Стек памет в Java

Stack Memory в Java се използва за разпределение на статична памет и изпълнение на нишка. Той съдържа примитивни стойности, които са специфични за даден метод и препратки към обекти, които са в купчина, посочени от метода.

Достъпът до тази памет е в реда на последно влизане (LIFO). Когато се извика нов метод, се създава нов блок отгоре на стека, който съдържа стойности, специфични за този метод, като примитивни променливи и препратки към обекти.

Когато методът завърши изпълнението, съответният кадър на стека се изтрива, потокът се връща към извикващия метод и пространството става достъпно за следващия метод.

2.1. Основни характеристики на стека памет

Освен това, което дискутирахме досега, следващи са и някои други характеристики на стековата памет:

  • Той расте и се свива, когато съответно се извикват и връщат нови методи
  • Променливите в стека съществуват само докато методът, който ги е създал, работи
  • Той автоматично се разпределя и освобождава, когато методът завърши изпълнението
  • Ако тази памет е пълна, Java хвърля java.lang.StackOverFlowError
  • Достъпът до тази памет е бърз в сравнение с купчината памет
  • Тази памет е безопасна за нишки, тъй като всяка нишка работи в свой собствен стек

3. Куп място в Java

Куп място в Java се използва за динамично разпределение на памет за Java обекти и JRE класове по време на изпълнение . Нови обекти винаги се създават в куп пространство и препратките към тези обекти се съхраняват в паметта на стека.

Тези обекти имат глобален достъп и могат да бъдат достъпни от всяко място в приложението.

Този модел памет е допълнително разделен на по-малки части, наречени поколения, това са:

  1. Младо поколение - тук се разпределят и състаряват всички нови обекти. Незначително събиране на боклука се случва, когато това се запълни
  2. Старо или временно поколение - тук се съхраняват дълго оцелели обекти. Когато обектите се съхраняват в младото поколение, се задава праг за възрастта на обекта и когато този праг бъде достигнат, обектът се премества в старото поколение
  3. Постоянно поколение - това се състои от JVM метаданни за класовете по време на изпълнение и методите на приложение

Тези различни части също са обсъдени в тази статия - Разлика между JVM, JRE и JDK.

Винаги можем да манипулираме размера на купчината памет според нашето изискване. За повече информация посетете тази свързана статия от Baeldung.

3.1. Основни характеристики на Java Heap Memory

Освен това, което дискутирахме досега, следва някои други характеристики на купчината пространство:

  • Достъпът до него се осъществява чрез сложни техники за управление на паметта, които включват младо поколение, старо или временно поколение и постоянно поколение
  • Ако пространството на купчината е запълнено, Java изхвърля java.lang.OutOfMemoryError
  • Достъпът до тази памет е относително по-бавен от стека
  • Тази памет, за разлика от стека, не се освобождава автоматично. Той се нуждае от Garbage Collector, за да освободи неизползвани обекти, за да запази ефективността на използването на паметта
  • За разлика от стека, купчината не е безопасна за нишки и трябва да бъде защитена чрез правилно синхронизиране на кода

4. Пример

Въз основа на наученото досега, нека анализираме прост Java код и нека да преценим как се управлява паметта тук:

class Person { int id; String name; public Person(int id, String name) { this.id = id; this.name = name; } } public class PersonBuilder { private static Person buildPerson(int id, String name) { return new Person(id, name); } public static void main(String[] args) { int id = 23; String name = "John"; Person person = null; person = buildPerson(id, name); } }

Нека анализираме тази стъпка по стъпка:

  1. Upon entering the main() method, a space in stack memory would be created to store primitives and references of this method
    • The primitive value of integer id will be stored directly in stack memory
    • The reference variable person of type Person will also be created in stack memory which will point to the actual object in the heap
  2. The call to the parameterized constructor Person(int, String) from main() will allocate further memory on top of the previous stack. This will store:
    • The this object reference of the calling object in stack memory
    • The primitive value id in the stack memory
    • The reference variable of String argument name which will point to the actual string from string pool in heap memory
  3. The main method is further calling the buildPerson() static method, for which further allocation will take place in stack memory on top of the previous one. This will again store variables in the manner described above.
  4. However, for the newly created object person of type Person, all instance variables will be stored in heap memory.

This allocation is explained in this diagram:

5. Summary

Before we conclude this article, let's quickly summarize the differences between the Stack Memory and the Heap Space:

Parameter Stack Memory Heap Space
Application Stack is used in parts, one at a time during execution of a thread The entire application uses Heap space during runtime
Size Stack has size limits depending upon OS and is usually smaller then Heap There is no size limit on Heap
Storage Stores only primitive variables and references to objects that are created in Heap Space All the newly created objects are stored here
Order It is accessed using Last-in First-out (LIFO) memory allocation system This memory is accessed via complex memory management techniques that include Young Generation, Old or Tenured Generation, and Permanent Generation.
Life Stack memory only exists as long as the current method is running Heap space exists as long as the application runs
Efficiency Comparatively much faster to allocate when compared to heap Slower to allocate when compared to stack
Allocation/Deallocation Тази памет се разпределя автоматично и освобождава, когато методът бъде извикан и върнат съответно Пространството за куп се разпределя, когато се създават и освобождават нови обекти от Gargabe Collector, когато към тях вече няма препратки

6. Заключение

Стекът и купчината са два начина, по които Java разпределя памет. В тази статия разбрахме как работят и кога да ги използваме за разработване на по-добри Java програми.

За да научите повече за управлението на паметта в Java, разгледайте тази статия тук. Също така обсъдихме JVM Garbage Collector, който е разгледан накратко в тази статия.