解决安全管理器下的许多域后,程序内存不足?

时间:2013-07-26 20:24:16

标签: java dns securitymanager

我有一项服务,要解析的域名来自不受信任的来源。最近,它因内存不足而崩溃。我缩小了可能的原因,并得出结论,它必须与最近的DNS请求流量有关。但是,该服务在解析域名后不存储任何内容,因此这似乎不太可能,但我尝试使用导致其解析域名的请求向我的服务发送垃圾邮件,以防万一。它确实死于此。然后,在得出代表我的代码没有存储内存之后,我将代码缩小到了这个范围:

import java.math.*;
import java.net.*;
class A {
    static {
        try {
            for (BigInteger i = BigInteger.ZERO; i==i; i = i.add(BigInteger.ONE))
                Inet4Address.getByName("a"+i+".dog");
        } catch (Exception e) {throw new RuntimeException(e);}
    }
}

我在/etc/dnsmasq.conf中使用此行设置了dnsmasq,以使分辨率更快:

address=/dog/127.0.0.1

起初我跑这个时,它存活了几天,所以看起来这不是问题。但后来我用我用来启动服务的脚本来运行它,它启用了安全管理器,它崩溃了:

$ javac A.java && java -Xmx80m -Djava.security.manager A
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Could not find the main class: A. Program will exit.

安全管理器使我的程序容易受到这种拒绝服务攻击。为什么?如何解决?


$ java -version
java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.6) (Gentoo build 1.6.0_27-b27)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

6 个答案:

答案 0 :(得分:5)

“InetAddress类有一个缓存来存储成功和不成功的主机名解析。 默认情况下,安装安全管理器时,为了防止DNS欺骗攻击,正主机名解析的结果将永久缓存。未安装安全管理器时,默认行为是缓存有限(依赖于实现)时间段的条目。主机名解析失败的结果会在很短的时间内(10秒)缓存,以提高性能。“

source:InetAddress.java的{javadoc http://docs.oracle.com/javase/6/docs/api/java/net/InetAddress.html

我认为它正在缓存所有永久解析的主机名并最终导致outOfMemoryError。

您可以尝试设置Java安全属性来控制TTL(生存时间)并查看这是否有助于解决此问题

答案 1 :(得分:3)

您正在静态块中执行长时间运行的代码。

当JVM加载一个类时,它首先执行静态块。 我怀疑是由于您的代码(本质上是一个长时间运行的操作)而导致JVM无法加载该类并崩溃。

通常在静态块中执行简单的初始化步骤。 将代码移动到静态main方法,然后重试。看看它是否能改善运行时间?

答案 2 :(得分:2)

为什么不想进行基本的分析?有几个问题是可能的,因此使用适当的工具五分钟肯定会有所帮助并节省您的时间。

<强> 1。没有SecurityManager的示例

enter image description here

<强> 2。您使用SecurityManager的示例

enter image description here

正如预期的那样,启用SecurityManager时会更多地使用内存。我没有设置任何DNS基础设施,因此请求率不是那么高。

重要提示:

  • 垃圾收集需要一些时间
  • 在某些情况下,默认GC没有提供足够的“吞吐量”,因此最终内存耗尽
  • VM内存模型并不那么简单
  • 默认虚拟机不提供实时性能保证

我建议您在使用您的设置对环境进行一些分析之前避免任何调整。我们可以花很多时间在这里尝试建议根本原因,但你会更快地找到答案。请尝试使用分析器,不要忘记分享您的结果。这是一个非常有趣的话题。

谢谢。

答案 3 :(得分:1)

我发现java.lang.OutOfMemoryError: Java heap space经常会产生误导,可能意味着你的Perm Space耗尽而不是你的终身对象。

尝试使用:-XX:MaxPermSize=128M

增加烫发空间

安全管理器无疑会增加加载到Perm中的类的数量。

答案 4 :(得分:0)

崩溃是否可以与-Djava.compiler=NONE重现?我想知道你是否遇到了JIT编译器错误。

另外,我很好奇在静态main方法中运行for循环时失败是否相同。我想知道在加载类时是否在静态块中执行长循环for循环是一个因素。

答案 5 :(得分:-1)

我仍然认为问题与OpenJDK有关。

有2个JDK具有生产质量:Sun(现在是Oracle)和IBM之一。

Gentoo是很好的Linux,但我认为你无法从GNU开源构建高质量的JDK。至少现在。悲伤,但却是真的。

尝试使用Sun JDK重现它。 http://www.gentoo.org/doc/en/java.xml

关于静态初始化块的评论值得关注。