Неочевидная утечка памяти

167
24 марта 2018, 16:37

Есть два сервера с идентичным ПО, железом и рабочим окружением. ОС старый добрый 6 дебиан. Разница лишь в количестве оперативки: 4 гига на тестовом и 128 на рабочем. Есть код на C++, который обрабатывает сетевые соединения, получает данные и пишет их в базу. При выполнении идентичного запроса на тестовом сервере использование оперативки и виртуальной памяти держится на одном уровне, а на рабочем только растет. Утечек памяти valgrind не нашел, структуры чисты, руками очищается даже выделяемая "лишняя" память векторов, плюс руками же чистится куча. Собственно вопрос: в какую сторону еще можно копнуть, чтобы разрешить проблему?

ps ef -o vsize,rss,%mem -p pidof непалюсь

Тестовый сервер

VSZ    RSS   %MEM 
448768 40832 0.6

Рабочий сервер

VSZ      RSS      %MEM
38446720 23682724 17.9
Answer 1

Для поиска неявных утечек можно воспользоваться другим инструментом valgrind'а: massif. Это профайлер кучи, который работает по следующему принципу: во время выполнения программы логируются все выделения/освобождения памяти, а также периодически делаются снимки использования памяти. В некоторых «детализированных» снимках сохраняется подробная статистика, сколько в каждой «точке аллокации» (функции в бектрейсе к malloc'у) было выделено, но не освобождено памяти. Логируются только точки аллокации, выделенная память из кучи к которым превосходит некий порог (по умолчанию ≥1% от общего объёма выделенного из кучи).

Тестовый пример

Пара контейнеров, которые равномерно заполняются и освобождаются, но в Стеке элемент «Забыли» извлечь:

#include <iostream>
#include <limits>
#include <memory>
#include <stack>
#include <queue>
#include <cstdlib>
class Container {
public:
    virtual void store(int s) = 0;
    virtual int unstore() = 0;
    virtual ~Container() {};
};
class Stack: public Container { 
    std::stack<int> data;
public:
    virtual void store(int s) { data.push(s); }
    virtual int unstore() { 
        if (data.size() !=0 ) {
            auto rv = data.top();
//            data.pop();
            return rv;
        } else {
            return std::numeric_limits<int>::min();
        }
    }
    virtual ~Stack() {};
};
class Queue: public Container { 
    std::queue<int> data;
public:
    virtual void store(int s) { data.push(s); }
    virtual int unstore() { 
        if (data.size() !=0 ) {
            auto rv = data.front();
            data.pop();
            return rv;
        } else {
            return std::numeric_limits<int>::min();
        }
    }
    virtual ~Queue() {};
};
int main(void) {
    std::unique_ptr<Container> cont1 (new Stack);
    std::unique_ptr<Container> cont2 (new Queue);
    for (int i = 0; i < 1024*1024; ++i) {
        int num = rand();
        if (num<RAND_MAX/4) {
            cont1->store(num);
        } else if (num<RAND_MAX/4*2) {
            cont1->unstore();
        } else if (num<RAND_MAX/4*3) {
            cont2->store(num);
        } else {
            cont2->unstore();
        }
    }
    return 0;
}

После запуска valgrind --tool=massif ./mem_eater получаем massif.out.28861.

Далее просматриваем его с помощью родной утилитки (к сожалению, сторонних графических инструментов для этого пока нет) ms_print massif.out.28861 и получаем здоровенную простынку с текстом (оставлена только одна секция для наглядности):

--------------------------------------------------------------------------------
Command:            ./mem_eater
Massif arguments:   (none)
ms_print arguments: massif.out.28861
--------------------------------------------------------------------------------

    MB
1.116^                                                                       #
     |                                                                    @@@#
     |                                                                @@@@@@@#
     |                                                            @:@@@@@@@@@#
     |                                                          @:@:@@@@@@@@@#
     |                                                      ::::@:@:@@@@@@@@@#
     |                                                 @@@:::: :@:@:@@@@@@@@@#
     |                                             @@@@@ @:::: :@:@:@@@@@@@@@#
     |                                          :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |                                      @:@@:@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |                                  ::::@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |                               :@@:: :@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |                          ::@:::@ :: :@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |                       :@:: @: :@ :: :@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |                  :::@@:@:: @: :@ :: :@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |              ::::: :@ :@:: @: :@ :: :@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |           @@:: ::: :@ :@:: @: :@ :: :@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |       :::@@ :: ::: :@ :@:: @: :@ :: :@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     |   ::::: :@@ :: ::: :@ :@:: @: :@ :: :@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
     | :@: ::: :@@ :: ::: :@ :@:: @: :@ :: :@:@ :@@@ @@@ @:::: :@:@:@@@@@@@@@#
   0 +----------------------------------------------------------------------->Mi
     0                                                                   302.7
Number of snapshots: 64
 Detailed snapshots: [2, 8, 9, 16, 17, 19, 22, 25, 30, 32, 34, 35, 36, 37, 38, 39, 40, 46, 48, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 (peak)]
--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
  0              0                0                0             0            0
  1      5,073,918           83,184           82,976           208            0
 .....
--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
 40    224,967,222          841,304          829,744        11,560            0
98.63% (829,744B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->87.51% (736,256B) 0x10AB96: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (new_allocator.h:104)
| ->87.51% (736,256B) 0x10A919: std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (alloc_traits.h:436)
|   ->87.51% (736,256B) 0x10A398: std::_Deque_base<int, std::allocator<int> >::_M_allocate_node() (stl_deque.h:600)
|     ->87.45% (735,744B) 0x109D4C: void std::deque<int, std::allocator<int> >::_M_push_back_aux<int const&>(int const&) (deque.tcc:471)
|     | ->87.45% (735,744B) 0x109875: std::deque<int, std::allocator<int> >::push_back(int const&) (stl_deque.h:1527)
|     |   ->87.03% (732,160B) 0x109499: std::stack<int, std::deque<int, std::allocator<int> > >::push(int const&) (stl_stack.h:219)
|     |   | ->87.03% (732,160B) 0x10912E: Stack::store(int) (mem_eater.cpp:19)
|     |   |   ->87.03% (732,160B) 0x108F11: main (mem_eater.cpp:55)
|     |   |     
|     |   ->00.43% (3,584B) in 1+ places, all below ms_print's threshold (01.00%)
|     |   
|     ->00.06% (512B) in 1+ places, all below ms_print's threshold (01.00%)
|     
->08.64% (72,704B) 0x4EC16EE: ??? (in /usr/lib64/gcc/x86_64-pc-linux-gnu/6.4.0/libstdc++.so.6.0.22)
| ->08.64% (72,704B) 0x400F448: call_init.part.0 (in /lib64/ld-2.25.so)
|   ->08.64% (72,704B) 0x400F559: _dl_init (in /lib64/ld-2.25.so)
|     ->08.64% (72,704B) 0x4000B88: ??? (in /lib64/ld-2.25.so)
|       
->02.45% (20,608B) 0x10AC08: __gnu_cxx::new_allocator<int*>::allocate(unsigned long, void const*) (new_allocator.h:104)
| ->02.45% (20,608B) 0x10A9DB: std::allocator_traits<std::allocator<int*> >::allocate(std::allocator<int*>&, unsigned long) (alloc_traits.h:436)
|   ->02.45% (20,608B) 0x10A566: std::_Deque_base<int, std::allocator<int> >::_M_allocate_map(unsigned long) (stl_deque.h:614)
|     ->02.45% (20,608B) 0x10A81A: std::deque<int, std::allocator<int> >::_M_reallocate_map(unsigned long, bool) (deque.tcc:929)
|     | ->02.45% (20,608B) 0x10A36D: std::deque<int, std::allocator<int> >::_M_reserve_map_at_back(unsigned long) (stl_deque.h:2116)
|     |   ->02.45% (20,608B) 0x109D34: void std::deque<int, std::allocator<int> >::_M_push_back_aux<int const&>(int const&) (deque.tcc:470)
|     |     ->02.45% (20,608B) 0x109875: std::deque<int, std::allocator<int> >::push_back(int const&) (stl_deque.h:1527)
|     |       ->02.43% (20,464B) 0x109499: std::stack<int, std::deque<int, std::allocator<int> > >::push(int const&) (stl_stack.h:219)
|     |       | ->02.43% (20,464B) 0x10912E: Stack::store(int) (mem_eater.cpp:19)
|     |       |   ->02.43% (20,464B) 0x108F11: main (mem_eater.cpp:55)
|     |       |     
|     |       ->00.02% (144B) in 1+ places, all below ms_print's threshold (01.00%)
|     |       
|     ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
|     
->00.02% (176B) in 1+ places, all below ms_print's threshold (01.00%)
--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
 41    230,069,860          857,944          846,128        11,816            0
 42    235,254,410          875,624          863,536        12,088            0
 43    240,656,059          892,784          880,432        12,352            0
 44    246,176,028          911,504          898,864        12,640            0
 45    251,968,045          931,264          918,320        12,944            0
 46    258,089,356          952,584          939,312        13,272            0
98.61% (939,312B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->88.79% (845,824B) 0x10AB96: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (new_allocator.h:104)
| ->88.79% (845,824B) 0x10A919: std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (alloc_traits.h:436)
|   ->88.79% (845,824B) 0x10A398: std::_Deque_base<int, std::allocator<int> >::_M_allocate_node() (stl_deque.h:600)
|     ->88.74% (845,312B) 0x109D4C: void std::deque<int, std::allocator<int> >::_M_push_back_aux<int const&>(int const&) (deque.tcc:471)
|     | ->88.74% (845,312B) 0x109875: std::deque<int, std::allocator<int> >::push_back(int const&) (stl_deque.h:1527)
|     |   ->88.47% (842,752B) 0x109499: std::stack<int, std::deque<int, std::allocator<int> > >::push(int const&) (stl_stack.h:219)
|     |   | ->88.47% (842,752B) 0x10912E: Stack::store(int) (mem_eater.cpp:19)
|     |   |   ->88.47% (842,752B) 0x108F11: main (mem_eater.cpp:55)
|     |   |     
|     |   ->00.27% (2,560B) in 1+ places, all below ms_print's threshold (01.00%)
|     |   
|     ->00.05% (512B) in 1+ places, all below ms_print's threshold (01.00%)
|     
->07.63% (72,704B) 0x4EC16EE: ??? (in /usr/lib64/gcc/x86_64-pc-linux-gnu/6.4.0/libstdc++.so.6.0.22)
| ->07.63% (72,704B) 0x400F448: call_init.part.0 (in /lib64/ld-2.25.so)
|   ->07.63% (72,704B) 0x400F559: _dl_init (in /lib64/ld-2.25.so)
|     ->07.63% (72,704B) 0x4000B88: ??? (in /lib64/ld-2.25.so)
|       
->02.16% (20,608B) 0x10AC08: __gnu_cxx::new_allocator<int*>::allocate(unsigned long, void const*) (new_allocator.h:104)
| ->02.16% (20,608B) 0x10A9DB: std::allocator_traits<std::allocator<int*> >::allocate(std::allocator<int*>&, unsigned long) (alloc_traits.h:436)
|   ->02.16% (20,608B) 0x10A566: std::_Deque_base<int, std::allocator<int> >::_M_allocate_map(unsigned long) (stl_deque.h:614)
|     ->02.16% (20,608B) 0x10A81A: std::deque<int, std::allocator<int> >::_M_reallocate_map(unsigned long, bool) (deque.tcc:929)
|     | ->02.16% (20,608B) 0x10A36D: std::deque<int, std::allocator<int> >::_M_reserve_map_at_back(unsigned long) (stl_deque.h:2116)
|     |   ->02.16% (20,608B) 0x109D34: void std::deque<int, std::allocator<int> >::_M_push_back_aux<int const&>(int const&) (deque.tcc:470)
|     |     ->02.16% (20,608B) 0x109875: std::deque<int, std::allocator<int> >::push_back(int const&) (stl_deque.h:1527)
|     |       ->02.15% (20,464B) 0x109499: std::stack<int, std::deque<int, std::allocator<int> > >::push(int const&) (stl_stack.h:219)
|     |       | ->02.15% (20,464B) 0x10912E: Stack::store(int) (mem_eater.cpp:19)
|     |       |   ->02.15% (20,464B) 0x108F11: main (mem_eater.cpp:55)
|     |       |     
|     |       ->00.02% (144B) in 1+ places, all below ms_print's threshold (01.00%)
|     |       
|     ->00.00% (0B) in 1+ places, all below ms_print's threshold (01.00%)
|     
->00.02% (176B) in 1+ places, all below ms_print's threshold (01.00%)
 .....

Из графика видно, что использование памяти для данного игрушечного примера постоянно растёт. А из последующего отчёта видно, что ко времени снимка 46 для хранения стека уже используется (845,824+20,608) байт, или же больше 90% всей кучи используемой программой, что указывает на очевидную ошибку. Интерпретация вывода не механическая и требует некоторых усилий и сноровки, но это помогает увидеть на что стоит обратить внимание.

Если поправить злосчастный комментарий, то получается практически чистый вывод с несколькими ложноположительными срабатываниями связанными с простым пиковым потреблением памяти:

--------------------------------------------------------------------------------
Command:            ./mem_eater
Massif arguments:   (none)
ms_print arguments: massif.out.29399
--------------------------------------------------------------------------------

    KB
77.60^                                #::     :                     :         
     |       :@:::::::::::::::::::::::#: :::::::::::::::::::::::@::::::::@::::
     | :::::::@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
     | :: :: :@::: ::: :: ::::: :::: :#: :: :::::::: :: :::::: :@::::::::@::::
   0 +----------------------------------------------------------------------->Mi
     0                                                                   319.7
Number of snapshots: 66
 Detailed snapshots: [7, 26 (peak), 50, 60]
--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
  0              0                0                0             0            0
  1      6,357,999           74,624           74,544            80            0
  2     11,037,520           74,104           74,032            72            0
  3     18,736,364           74,104           74,032            72            0
  4     23,440,137           74,104           74,032            72            0
  5     27,510,682           74,104           74,032            72            0
  6     33,147,787           75,664           75,568            96            0
  7     38,465,295           75,664           75,568            96            0
99.87% (75,568B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->96.09% (72,704B) 0x4EC16EE: ??? (in /usr/lib64/gcc/x86_64-pc-linux-gnu/6.4.0/libstdc++.so.6.0.22)
| ->96.09% (72,704B) 0x400F448: call_init.part.0 (in /lib64/ld-2.25.so)
|   ->96.09% (72,704B) 0x400F559: _dl_init (in /lib64/ld-2.25.so)
|     ->96.09% (72,704B) 0x4000B88: ??? (in /lib64/ld-2.25.so)
|       
->03.38% (2,560B) 0x10AC9E: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (new_allocator.h:104)
| ->03.38% (2,560B) 0x10AA21: std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (alloc_traits.h:436)
|   ->03.38% (2,560B) 0x10A4A0: std::_Deque_base<int, std::allocator<int> >::_M_allocate_node() (stl_deque.h:600)
|     ->02.71% (2,048B) 0x109DD6: void std::deque<int, std::allocator<int> >::_M_push_back_aux<int const&>(int const&) (deque.tcc:471)
|     | ->02.71% (2,048B) 0x1098A1: std::deque<int, std::allocator<int> >::push_back(int const&) (stl_deque.h:1527)
|     |   ->02.03% (1,536B) 0x1095AF: std::queue<int, std::deque<int, std::allocator<int> > >::push(int const&) (stl_queue.h:243)
|     |   | ->02.03% (1,536B) 0x109232: Queue::store(int) (mem_eater.cpp:35)
|     |   |   ->02.03% (1,536B) 0x108F5E: main (mem_eater.cpp:59)
|     |   |     
|     |   ->00.68% (512B) in 1+ places, all below ms_print's threshold (01.00%)
|     |   
|     ->00.68% (512B) in 1+ places, all below ms_print's threshold (01.00%)
|     
->00.40% (304B) in 1+ places, all below ms_print's threshold (01.00%)
--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
  8     43,466,034           75,664           75,568            96            0
  9     50,687,976           75,744           75,648            96            0
 10     54,674,907           76,784           76,672           112            0
 11     61,489,426           76,784           76,672           112            0
 12     66,913,719           76,784           76,672           112            0
 13     73,503,124           76,784           76,672           112            0
 14     80,840,510           75,744           75,648            96            0
 15     85,776,021           75,744           75,648            96            0
 16     93,894,556           76,784           76,672           112            0
 17     98,955,219           76,264           76,160           104            0
 18    104,342,732           76,784           76,672           112            0
 19    109,566,108           75,744           75,648            96            0
 20    116,286,750           76,784           76,672           112            0
 21    124,342,177           76,784           76,672           112            0
 22    128,350,479           77,824           77,696           128            0
 23    133,653,415           76,264           76,160           104            0
 24    139,392,895           77,824           77,696           128            0
 25    144,750,550           78,864           78,720           144            0
 26    151,838,741           79,464           79,312           152            0
99.81% (79,312B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->91.49% (72,704B) 0x4EC16EE: ??? (in /usr/lib64/gcc/x86_64-pc-linux-gnu/6.4.0/libstdc++.so.6.0.22)
| ->91.49% (72,704B) 0x400F448: call_init.part.0 (in /lib64/ld-2.25.so)
|   ->91.49% (72,704B) 0x400F559: _dl_init (in /lib64/ld-2.25.so)
|     ->91.49% (72,704B) 0x4000B88: ??? (in /lib64/ld-2.25.so)
|       
->07.73% (6,144B) 0x10AC9E: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (new_allocator.h:104)
| ->07.73% (6,144B) 0x10AA21: std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (alloc_traits.h:436)
|   ->07.73% (6,144B) 0x10A4A0: std::_Deque_base<int, std::allocator<int> >::_M_allocate_node() (stl_deque.h:600)
|     ->07.09% (5,632B) 0x109DD6: void std::deque<int, std::allocator<int> >::_M_push_back_aux<int const&>(int const&) (deque.tcc:471)
|     | ->07.09% (5,632B) 0x1098A1: std::deque<int, std::allocator<int> >::push_back(int const&) (stl_deque.h:1527)
|     |   ->03.87% (3,072B) 0x1095AF: std::queue<int, std::deque<int, std::allocator<int> > >::push(int const&) (stl_queue.h:243)
|     |   | ->03.87% (3,072B) 0x109232: Queue::store(int) (mem_eater.cpp:35)
|     |   |   ->03.87% (3,072B) 0x108F5E: main (mem_eater.cpp:59)
|     |   |     
|     |   ->03.22% (2,560B) 0x1094A9: std::stack<int, std::deque<int, std::allocator<int> > >::push(int const&) (stl_stack.h:219)
|     |     ->03.22% (2,560B) 0x10912E: Stack::store(int) (mem_eater.cpp:19)
|     |       ->03.22% (2,560B) 0x108F11: main (mem_eater.cpp:55)
|     |         
|     ->00.64% (512B) in 1+ places, all below ms_print's threshold (01.00%)
|     
->00.58% (464B) in 1+ places, all below ms_print's threshold (01.00%)
 .....
--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
 61    318,903,255           77,384           77,264           120            0
 62    322,953,503           77,384           77,264           120            0
 63    327,012,737           77,384           77,264           120            0
 64    331,088,164           76,864           76,752           112            0
 65    335,212,302           76,864           76,752           112            0

Другие утилиты

Кроме massif в valgrind'е есть другая схожая утилита: DHAT (exp-dhat). Она работает несколько на другом принципе: для каждой точки аллокации она собирает статистику по количеству аллокаций/деаллокаций, чтениям/записям, а также времени жизни аллокаций. Её также возможно использовать для неявных утечек, но ИМХО вывод оной интерпретировать сложнее и её лучше оставить для поиска более тонких ошибок/оптимизаций: поиска сохраняемых, но не читаемых данных, оптимизаций избыточной аллокации, поиск выделений слишком больших блоков итп.

READ ALSO
Как найти следующее четное число?

Как найти следующее четное число?

на вход дается положительное целое число, нужно найти последующее четное число, причем программа должна быть БЕЗ использования условного...

266
Как в JFrame взаимодействовать с переменными, созданными в разных методах actionPerformed?

Как в JFrame взаимодействовать с переменными, созданными в разных методах actionPerformed?

В методе actionPerformed одной JButton у меня выполняются определенные операции с переменными, например:

145
Цикл по связанным объектам

Цикл по связанным объектам

Имеется объект типа Entry со своими полями где хранятся ключ (Long) и значение (String) и ссылка на следующий объект этого же типаЭти объекты в свою...

232
Немного вопросов о многопоточности

Немного вопросов о многопоточности

Сам не первый год пишу на java, но лишь в рамках хобби, с многопоточностью приходится не так часто работать

184