Maison  >  Article  >  Java  >  Quelle est la raison pour laquelle ThreadLocal en Java provoque un débordement de mémoire (Out Of Memory) ?

Quelle est la raison pour laquelle ThreadLocal en Java provoque un débordement de mémoire (Out Of Memory) ?

WBOY
WBOYavant
2023-04-23 23:58:091052parcourir

Analyse des causes

Quelle est la raison pour laquelle ThreadLocal provoque un MOO mémoire ?

La couche inférieure de ThreadLocal stocke les données via ThreadLocalMap

Le code source est le suivant :

Quelle est la raison pour laquelle ThreadLocal en Java provoque un débordement de mémoire (Out Of Memory) ?

  • Lorsque nous utilisons ThreadLocal.set(), la valeur et la clé de l'ensemble (c'est-à-dire, la classe ThreadLocal définie par l'entreprise elle-même) sera stockée dans Le code source

dans le tableau Entry[] de ThreadLocalMap est le suivant :

Quelle est la raison pour laquelle ThreadLocal en Java provoque un débordement de mémoire (Out Of Memory) ?

  • où Entry implémente une référence faible WeakReference, et la clé d'entrée (c'est-à-dire la classe ThreadLocal définie par l'entreprise) sera regroupée dans une référence faible et est utilisée comme clé d'entrée. La définition de la référence faible de Java est que lorsque la JVM effectue une analyse de récupération de place et trouve un objet avec uniquement des références faibles, elle recyclera immédiatement l'objet. C'est un moyen d'éviter un débordement de mémoire lorsque ThreadLocal a été conçu à l'origine

. Le code source est le suivant :

Quelle est la raison pour laquelle ThreadLocal en Java provoque un débordement de mémoire (Out Of Memory) ?

Bien que la clé soit conditionnée dans une référence faible et sera recyclée par le mécanisme de récupération de place, la valeur peut avoir une chaîne de référence forte lorsque le thread (Thread) ne meurt pas.

En raison de value est une référence forte. Tant que Thread ne meurt pas, comme un pool de threads, cette chaîne de référence forte existera, alors value. ne sera pas recyclé, provoquant éventuellement un débordement de mémoirevalue是强引用,只要 Thread不死亡时,例如线程池,这条强引用链就会存在,那么value就不会回收,可能造成内存溢出

引用关系如下: Thread ==> ThreadLocalMap ==> Entry ==> value

但是这个消除强引用链的动作是需要业务方在get的情况下触发的,可能业务方并不会get、也可能get是key不为空,并不会触发 expungeStaleEntry 类。所以开发者要养成良好的习惯,记得用完 ThreadLocal 时,调一次ThreadLocal.remove()方法或者 ThreadLocal.set(null)

La relation de référence est la suivante :

Thread ==> ThreadLocalMap ==> Entry value ==> La chaîne nécessite que la partie commerciale la déclenche en cas d'obtention, ce qui peut être la partie commerciale ne l'obtiendra pas, ou il se peut que la clé ne soit pas vide et que la classe expungeStaleEntry ne soit pas déclenchée. Par conséquent, les développeurs doivent développer de bonnes habitudes et n'oubliez pas d'appeler la méthode ThreadLocal.remove() ou ThreadLocal.set(null) lorsqu'ils ont fini d'utiliser ThreadLocal code> code><p><strong>Utilisation correcte</strong><pre class="brush:java;">public class ThreadLocalTest { /** * 未初始化的本地线程变量 */ private static ThreadLocal&lt;User&gt; userThreadLocal = new ThreadLocal&lt;&gt;(); public static void main(String[] args) throws InterruptedException { int threadNum = 10; List&lt;Thread&gt; threadList = Lists.newArrayList(); for (int i = 0; i &lt; threadNum; ++i) { long userId = i; Thread t = new Thread(() -&gt; { try { // 设置变量值 userThreadLocal.set(new User(userId, &quot;lanxing&quot; + userId, &quot;2x&quot;)); // 使用变量 doSomething(); } finally { // 移除变量 userThreadLocal.remove(); //移除ThreadLocal变量 } }, &quot;T&quot; + i); threadList.add(t); t.start(); } for (int i = 0; i &lt; threadNum; ++i) { threadList.get(i).join(); } } private static void doSomething() { log.info(&quot;Use ThreadLocal variable :{}&quot;, JSON.toJSONString(userThreadLocal.get())); } } @Data @NoArgsConstructor @AllArgsConstructor class User { private Long id; private String name; private String level; }</pre></p> <blockquote>Résultat d'impression :<p><br><br><br>14:30:26.790 [T2] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal :{"id":2," level":"2x","name":"lanxing2"}<br>14:30:26.789 [T5] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal :{"id":5,"level": "2x", "name": "lanxing5"}<br>14: 30: 26.792 [T0] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal : {"id": 0, "level": "2x" ,"name": "lanxing0"}<br>14:30:26.792 [T4] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal :{"id":4,"level":"2x","name ":"lanxing4"}<br>14:30:26.792 [T8] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal :{"id":8,"level":"2x","name":" lanxing8"}<br>14:30:26.791 [T1] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal :{"id":1,"level":"2x","name":"lanxing1"} <br>14:30:26.792 [T7] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal :{"id":7,"level":"2x","name":"lanxing7"}</p>14 : 30:26.792 [T6] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal :{"id":6,"level":"2x","name":"lanxing6"}</blockquote>14:30:26.791 [T9] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal :{"id":9,"level":"2x","name":"lanxing9"}🎜14:30:26.790 [T3] INFO io.zhengsh.order.tool.ThreadLocalTest - Utiliser la variable ThreadLocal :{"id":3,"level":"2x","name":"lanxing3"}🎜🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer