>  기사  >  Java  >  Java에서 ThreadLocal이 메모리 오버플로(Out Of Memory)를 일으키는 이유는 무엇입니까?

Java에서 ThreadLocal이 메모리 오버플로(Out Of Memory)를 일으키는 이유는 무엇입니까?

WBOY
WBOY앞으로
2023-04-23 23:58:091081검색

원인 분석

ThreadLocal이 메모리 OOM을 일으키는 이유는 무엇인가요?

ThreadLocal의 맨 아래 레이어는 ThreadLocalMap을 통해 데이터를 저장합니다.

소스 코드는 다음과 같습니다.

Java에서 ThreadLocal이 메모리 오버플로(Out Of Memory)를 일으키는 이유는 무엇입니까?

  • ThreadLocal.set()을 사용할 때 해당 집합의 값과 키(즉, 비즈니스 자체에서 정의한 ThreadLocal 클래스)은 ThreadLocalMap의 Entry[] 배열에 있는

소스 코드는 다음과 같습니다.

Java에서 ThreadLocal이 메모리 오버플로(Out Of Memory)를 일으키는 이유는 무엇입니까?

  • 여기서 Entry는 약한 참조 WeakReference를 구현합니다. Entry 키(즉, 비즈니스 당사자가 정의한 ThreadLocal 클래스)는 Weak 참조로 패키징되어 Entry 키로 사용됩니다. Java의 약한 참조에 대한 정의는 JVM이 가비지 수집 검색을 수행하고 약한 참조만 있는 개체를 찾으면 즉시 개체를 재활용한다는 것입니다. 이는 ThreadLocal이 원래 설계되었을 때 메모리 오버플로를 방지하는 수단입니다

소스 코드는 다음과 같습니다.

Java에서 ThreadLocal이 메모리 오버플로(Out Of Memory)를 일으키는 이유는 무엇입니까?

키가 약한 참조로 패키징되어 가비지 수집 메커니즘에 의해 재활용되지만 값은 스레드(Thread)가 죽지 않을 때 강력한 참조 체인을 가질 수 있습니다.

은 스레드 풀과 같이 스레드가 죽지 않는 한 이 강력한 참조 체인이 존재하므로 값입니다. 는 재활용되지 않으며 메모리 오버플로가 발생할 수 있습니다value是强引用,只要 Thread不死亡时,例如线程池,这条强引用链就会存在,那么value就不会回收,可能造成内存溢出

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

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

참조 관계는 다음과 같습니다.

Thread ==> ThreadLocalMap ==> Entry ==> 체인은 비즈니스 당사자가 가져오기의 경우 이를 트리거하도록 요구하며, 비즈니스 당사자가 이를 가져오지 못하거나 키가 비어 있지 않아 expungeStaleEntry 클래스가 트리거되지 않을 수 있습니다. 따라서 개발자는 좋은 습관을 기르고 ThreadLocal 사용이 끝나면 ThreadLocal.remove() 메서드 또는 ThreadLocal.set(null)을 호출하는 것을 기억해야 합니다. code>

올바른 사용법

public class ThreadLocalTest {
    /**
     * 未初始化的本地线程变量
     */
    private static ThreadLocal<User> userThreadLocal = new ThreadLocal<>();
    public static void main(String[] args) throws InterruptedException {
        int threadNum = 10;
        List<Thread> threadList = Lists.newArrayList();

        for (int i = 0; i < threadNum; ++i) {
            long userId = i;
            Thread t = new Thread(() -> {
                try {
                    // 设置变量值
                    userThreadLocal.set(new User(userId, "lanxing" + userId, "2x"));
                    // 使用变量
                    doSomething();
                } finally {
                    // 移除变量
                    userThreadLocal.remove();   //移除ThreadLocal变量
                }
            }, "T" + i);
            threadList.add(t);
            t.start();
        }

        for (int i = 0; i < threadNum; ++i) {
            threadList.get(i).join();
        }
    }
    private static void doSomething() {
        log.info("Use ThreadLocal variable :{}", JSON.toJSONString(userThreadLocal.get()));
    }
}
@Data
@NoArgsConstructor
@AllArgsConstructor
class User {
    private Long id;
    private String name;
    private String level;
}

인쇄 결과:




14:30:26.790 [T2] INFO io.zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용:{"id":2," level" :"2x","name":"lanxing2"}
14:30:26.789 [T5] 정보 io.zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용 :{"id":5,"level": "2x ","name":"lanxing5"}
14:30:26.792 [T0] 정보 io.zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용 :{"id":0,"level":"2x" ," name":"lanxing0"}
14:30:26.792 [T4] 정보 io.zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용:{"id":4,"level":"2x","name ": "lanxing4"}
14:30:26.792 [T8] 정보 io.zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용:{"id":8,"level":"2x","name":" lanxing8" }
14:30:26.791 [T1] 정보 io.zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용 :{"id":1,"level":"2x","name":"lanxing1"}
14 :30:26.792 [T7] 정보 io.zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용:{"id":7,"level":"2x","name":"lanxing7"}

14: 30: 26.792 [T6] 정보 io.zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용:{"id":6,"level":"2x","name":"lanxing6"}
14:30:26.791 [T9 ] INFO io.zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용:{"id":9,"level":"2x","name":"lanxing9"}🎜14:30:26.790 [T3] INFO io .zhengsh.order.tool.ThreadLocalTest - ThreadLocal 변수 사용:{"id":3,"level":"2x","name":"lanxing3"}🎜🎜

위 내용은 Java에서 ThreadLocal이 메모리 오버플로(Out Of Memory)를 일으키는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제