OutOfMemoryError - почему ожидание может Распараллелить не быть собранным "мусор"?

Редактировать: Используя классический балансировщик нагрузки ...

LoadBalancer:
  Type: 'AWS::ElasticLoadBalancing::LoadBalancer'
  Properties:
    HealthCheck:
      HealthyThreshold: '2'
      Interval: '15'
      Target: 'HTTP:9000/'
      Timeout: '5'
      UnhealthyThreshold: '10'
    Listeners: !If 'HasTCPPort1'
      -
        - InstancePort: TCPPort1
          Condition: HasTCPPort1
          InstanceProtocol: HTTP
          LoadBalancerPort: TCPPort1
          SSLCertificateId: !If
            - HasLoadBalancerCertificateARN
            - !Ref LoadBalancerCertificateARN
            - !Ref 'AWS::NoValue'
          Protocol: !If
            - HasLoadBalancerCertificateARN
            - HTTPS
            - HTTP
      - !Ref 'AWS::NoValue' 
    Scheme: internet-facing
    Subnets:
      - 'Fn::ImportValue':
            !Sub '${ParentVPCStack}-SubnetAPublic'
      - 'Fn::ImportValue':
            !Sub '${ParentVPCStack}-SubnetBPublic'
      - 'Fn::ImportValue':
            !Sub '${ParentVPCStack}-SubnetCPublic'
    SecurityGroups:
      - !Ref SecurityGroup
    Instances:
      - !Ref Server
5
задан martinus 24 April 2009 в 09:17
поделиться

7 ответов

Потоки являются объектами верхнего уровня. Они «особенные», поэтому они не следуют тем же правилам, что и другие объекты. Они не полагаются на ссылки, чтобы сохранить их «живыми» (то есть в безопасности от GC). Поток не будет собирать мусор, пока не закончится. Что не происходит в вашем примере кода, так как поток заблокирован. Конечно, теперь, когда объект потока не является сборщиком мусора, любой другой объект, на который он ссылается (очередь в вашем случае), также не может быть сборщиком мусора.

8
ответ дан 18 December 2019 в 12:01
поделиться

Вы создаете потоки на неопределенный срок, потому что они все блокируются, пока ArrayBlockingQueue abq не имеет какой-либо записи. Таким образом, в конечном итоге вы получите OutOfMemoryError .

(edit)

Каждый созданный вами поток никогда не закончится, потому что он блокируется до очереди abq как одна запись. Если поток работает, GC не собирается собирать объекты, на которые ссылается поток, включая очередь abq и сам поток.

5
ответ дан 18 December 2019 в 12:01
поделиться

Did you use a C# library earlier?

In C++, no standard library function for Bezier curves is available (yet). You can of course roll your own (CodeProject sample) or look for a math library.

This blogpost explains the idea nicely but in Actionscript. Translation should not be much of a problem.

--121 --- 2574310--
abq.put(0);

должен спасти ваш день.

Все ваши потоки ждут в своей очереди take () , но вы никогда ничего не помещаете в эти очереди.

2
ответ дан 18 December 2019 в 12:01
поделиться

Ваш цикл while является бесконечным циклом и непрерывно создает новые потоки. Хотя вы запускаете выполнение потока, как только он создан, но время, затрачиваемое на выполнение задачи потоком, больше, чем время, затрачиваемое на создание потока.

Кроме того, что вы делаете с параметром abq, объявив его внутри цикл while?

На основании ваших правок и других комментариев. System.gc () не гарантирует цикл GC. Прочитайте мое утверждение выше, скорость исполнения вашего потока ниже, чем скорость создания.

Я проверил комментарий для метода take () «Извлекает и удаляет заголовок этой очереди, ожидая, если в этой очереди нет элементов». Я вижу, вы определяете ArrayBlockingQueue, но вы не добавляете к нему никаких элементов, поэтому все ваши потоки просто ждут этого метода,

0
ответ дан 18 December 2019 в 12:01
поделиться

I do not know how threads are implemented in Java, but one possible reason comes to mind why the queues and threads are not collected: The threads may be wrappers for system threads using system synchronization primitives, in which case the GC cannot automatically collect a waiting thread, since it cannot tell whether the thread is alive or not, i.e. the GC simply does not know that a thread cannot be woken.

I can't say what's the best way to fix it, since I'd need to know what you are trying to do, but you could look at java.util.concurrent to see if it has classes for doing what you need.

0
ответ дан 18 December 2019 в 12:01
поделиться

Вы запускаете поток, поэтому все эти новые потоки будут работать асинхронно, пока цикл продолжает создавать новые.

Поскольку ваш код блокируется, потоки являются ссылками жизни в системе и не могут быть собраны. Но даже если бы они выполняли какую-то работу, потоки вряд ли прекратят работать так же быстро, как они созданы (по крайней мере, в этом примере), и поэтому GC не сможет собрать всю память и в конечном итоге завершится с ошибкой OutOfMemoryException.

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

0
ответ дан 18 December 2019 в 12:01
поделиться

Вызов System.gc ничего не делает, потому что нечего собирать. Когда поток запускается, он увеличивает счетчик ссылок на потоки, если этого не сделать, поток будет прерываться неопределенно. Когда метод run потока завершается, то счетчик ссылок потока уменьшается.

while (true) {
    // just a simple demo, not useful code.
    // 0 0 - the first number is thread reference count, the second is abq ref count
    final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<Integer>(2);
    // 0 1
    final Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                abq.take();
                // 2 2
            } catch (final InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    // 1 1
    t.start();
    // 2 2 (because the run calls abq.take)
    // after end of loop
    // 1 1 - each created object's reference count is decreased
}

Теперь существует потенциальное условие гонки - что, если основной цикл завершается и выполняет сборку мусора до того, как поток t сможет выполнить какую-либо обработку, т.е. он приостановлен ОС до выполнения оператора abq.take? Метод run попытается получить доступ к объекту abq после того, как GC выпустил его, что было бы плохо.

Чтобы избежать состояния гонки, вы должны передать объект в качестве параметра методу выполнения. Я не уверен насчет Java в эти дни, это было давно, поэтому я d предлагает передать объект в качестве параметра конструктора классу, производному от Runnable . Таким образом, перед вызовом метода run делается дополнительная ссылка на abq, что гарантирует, что объект всегда будет действительным.

0
ответ дан 18 December 2019 в 12:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: