项目中某类static初始化线程时遇内存不足异常及后续的NoClassDefFoundError异常记录

最近,我发现该项目的情况相对有趣,因此我将在此处记录下来。

项目中某类static初始化线程时遇内存不足异常及后续的NoClassDefFoundError异常记录

一类在静态初始化代码块中启动线程,以监视类的操作并打印日志。代码如下。

public class Test {
  
   static {
      new Thread(new Runnable(){}).start();
   }
   ...// other code
}

在项目操作期间,有一个需要此类的地方。加载类时,机器在此时间点无法使用足够的内存,从而导致线程启动故障并引发异常:java.lang.outofmemoryerror:无法创建新的本机线程。此例外很容易理解,但后来发现同样的例外正在打印:

java.lang.noclassdeffounderror:无法初始化类xx.xx.test(上面定义的测试类)

根据上下文,可以猜测,在静态块中创建线程时会抛出的OutofMemoryError导致测试类不再加载,从而导致随后的一系列NoclassDeffoundErrors。为了验证这个猜想,我编写了一个代码来对其进行测试

import java.util.Date;
import org.apache.commons.lang3.time.DateUtils;
/**
 * @author klein.lei
 * @version $Id: TestStaticError.java, v 0.1 2018年02月27日 下午8:28 klein.lei Exp $
 */
public class TestStaticError {
    static {
        if (new Date().after(DateUtils.addDays(new Date(), -1))) { // 这里是为了保证一定抛出该异常,如果你在static块中直接抛异常,编译无法通过
            throw new RuntimeException();
        }
    }
    public void test1() {
        System.out.println("hello world");
    }
}

主要方法

import java.util.Scanner;
/**
 * @author klein.lei
 * @version $Id: Test.java, v 0.1 2018年02月27日 下午8:28 klein.lei Exp $
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                TestStaticError testStaticError = new TestStaticError();
                testStaticError.test1();
            }
        }).start();
        Thread.sleep(200L);
        for (int i = 0; i < 10; i ++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    TestStaticError testStaticError = new TestStaticError();
                    testStaticError.test1();
                }
            }).start();
        }
        new Scanner(System.in).next();
    }
}

跑步可以得到以下结果

Exception in thread "Thread-0" java.lang.ExceptionInInitializerError
	at learning.web.Test$1.run(Test.java:19)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException
	at learning.web.TestStaticError.(TestStaticError.java:19)
	... 2 more
Exception in thread "Thread-1" Exception in thread "Thread-2" java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-4" Exception in thread "Thread-3" java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-6" java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-10" Exception in thread "Thread-5" java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-9" Exception in thread "Thread-8" java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-7" java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)
java.lang.NoClassDefFoundError: Could not initialize class learning.web.TestStaticError
	at learning.web.Test$2.run(Test.java:28)
	at java.lang.Thread.run(Thread.java:745)

可以发现,第一次是RuntimeException,其次是Java.lang.noclassdeffounderror,表明上述猜测是正确的。至于为什么发生这种情况,它可能需要将Classloader的源代码加倍。

在Google之后,我找到了答案。有人在stackoverflow上问了这个问题(单击以打开链接)(当然,程序员需要掌握面向stackoverflow的编程)

让我们简要总结:

我们知道Java中的每个C类都有一个相应的类对象(Java.lang.class)。此类对象用于描述有关C类的一些信息,包括C类C的状态C类描述C类。

1。C类已通过验证和准备阶段,但尚未初始化。

(注意:类加载过程)

2。C类是由其他线程初始化的。

3。C类已由其他线程初始化。

4。C类处于错误状态,这可能是由于尝试初始化时的失败。

根据Oracle提供的文档(),JVM在初始化类时必须严格遵守以下规范:

1。对于每个C类,都有一个唯一的初始化锁定LC。初始化类时,当前线程必须首先获取锁。

2。根据C类的类对象的状态指示,如果C类由其他线程初始化,则释放当前锁定LC,并且当前线程被阻止,直到班级初始化完成为止。

3。根据C类的类对象的状态指示,如果C类由当前线程初始化,则意味着它是一个递归调用,需要发布锁定LC,并且请求正常结束。

4。根据C类的类对象的状态指示,如果初始化了C类,则需要发布锁定LC,并且请求正常终止。

5。根据C类的类对象的状态指示,如果C类处于错误状态,则意味着类的初始化无法完成。目前,您需要释放锁并扔一个NoclassDeffoundError。

6。如果在2、3、4和5中不是这种情况,则意味着当前线程可以正常初始化类。目前,有必要在C的类对象中记录当前线程的初始化C类,然后释放锁定LC,然后将其初始化。在编译过程中可以确定的C和其他常数字段中的最终场。

7。如果C类不是接口,并且尚未初始化C的父级SC,请重复对SC初始化类的所有步骤。如有必要,请先验证并准备SC。如果在SC的初始化过程中引发了异常,则初始化过程将出乎意料地中止,然后需要获取锁。 C类在C类的类对象中标记为错误状态。标记完成后,其他等待线程释放锁定LC,最后在SC初始化过程中引发了该过程的同一例外,从而流产了类的初始化过程C

8。接下来,确定C类的断言()是否生效。

9。接下来,遵循代码文本定义的顺序(注意:

public class {
   int a = getA();
   int b = getB();
}

这里的文本顺序是指第一个初始化,然后是b),初始化类的字段,静态块代码和接口上定义的字段。

10。如果此执行过程正常结束,则获取了锁定液压,则标记为C类标记的类对象已完全初始化,所有其他线程均已唤醒,锁定锁定,并且该过程通常结束。

11。如果在此执行过程中发生例外,则抛出异常E,导致该过程不小心流产。如果此异常不是错误或错误的子类,请创建一个异常的依属二氨基烯词,并将E用作异常的构造函数参数。在下一步中,用ExcepeninInitializerError替换E。如果由于OUTOFMEMORYERROR错误而无法创建异常的initializerError对象,请在下一步中将E替换为OutofMemoryError。

12.尝试获取锁定LC,将C类的类对象标记为错误的状态,唤起所有等待线程,释放锁定LC,并以Exception e(或ExceptionininitialInitializerError或OutofmemoryError)出现在步骤中11。

根据上述步骤,我们可以发现静态块的代码初始化是在步骤9中初始化的。如果此时抛出了异常,则抛出了一个异常的,它符合我们的测试代码,因为它符合我们的测试代码,因为类的初始化过程全部锁定,当第一个线程加载类时,类状态被标记为错误状态。当其他线程再次加载类时,它们会直接输入步骤5中描述的过程并将其投掷。 NoclassDeffoundError也匹配我们的测试代码的性能。

在这一点上,整个例外的原因也很清楚。在代码编写过程中,我们应该尽量避免在静态块代码或类成员变量中抛出异常,因为一旦在初始化过程中,不能重试的类初始化过程。如果发生例外,则将在此后正常加载类。

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

23阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

27阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

23阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读