来自Collections.unmodifiableMap get()的StackOverflowError吗? [英] StackOverflowError from Collections.unmodifiableMap get()?

查看:50
本文介绍了来自Collections.unmodifiableMap get()的StackOverflowError吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚获得了以下堆栈跟踪:

i was just handed the following stack trace:

2015-12-20 07:43:36.151 -0800 ERROR o.s.s.s.TaskUtils$LoggingErrorHandler [taskExecutor-6] Unexpected error occurred in scheduled task.
java.lang.StackOverflowError
    at java.util.Collections$UnmodifiableMap.get(Collections.java:1454) ~[?:1.8.0_65]
    at java.util.Collections$UnmodifiableMap.get(Collections.java:1454) ~[?:1.8.0_65]
    at java.util.Collections$UnmodifiableMap.get(Collections.java:1454) ~[?:1.8.0_65]
    at java.util.Collections$UnmodifiableMap.get(Collections.java:1454) ~[?:1.8.0_65]

查看源代码,这是get()的含义(Collections.java:1454):

looking at the source code this is the impl of get() (Collections.java:1454):

public V get(Object key)                 {return m.get(key);}

所以只有在不知不觉中this.m = this的情况下才有可能,但我无法重现这种情况.

so this should only be possible if somehow this.m = this, but i cannot reproduce such a scenario.

这怎么可能?

推荐答案

要详细说明Sotirios的评论:可以通过以下方式重新表现该行为:

To elaborate the comment by Sotirios: The behavior can be reporoduced with something like this:

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class UnmodifiableMapStackOverflow
{
    public static void main(String[] args)
    {
        int depth = 20000; 
        test(depth);
    }

    private static void test(int depth)
    {
        Map<String, String> map = new HashMap<String, String>();
        map.put("X", "Y");
        for (int i =0; i<depth; i++)
        {
            map = Collections.unmodifiableMap(map);
        }
        String value = map.get("X");
        System.out.println("At "+depth+" got "+value);
    }
}

( depth 所需的值可能取决于很多因素,毫无疑问,您可能必须增加该值才能观察到效果).

(The value that is required for the depth may depend on many, many factors - in doubt, you may have to increase it to observe the effect).

当然,此代码是公然的,显然是错误的.关键是您可能会意外地执行类似的操作.更为复杂的情况如下:

Of course, this code is blatantly and obviously wrong. The key point is that you might accidentally do something similar. A more complex scenario might be the following:

  • 使用 setMap 方法
  • 将地图存储在字段中
  • 通过 getMap 方法返回地图.但是由于您通常不应该返回可修改的内部数据结构,因此会返回不可修改的视图.
  • 再次设置此不可修改的视图,在每次通话期间在原始恶意事件周围造成一个层".
  • The map is stored in a field, using a setMap method
  • The map is returned in a getMap method. But becuase you should usually not return modifiable internal data structures, an unmodifiable view is returned.
  • This unmodifiable view is set again, causing one "layer" around the original mal during each call.

类似于此代码:

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

public class UnmodifiableMapStackOverflowComplex
{
    public static void main(String[] args)
    {
        UnmodifiableMapStackOverflowComplex c = 
            new UnmodifiableMapStackOverflowComplex();

        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put("X", "Y");
        c.setMap(map);

        for (int i=0; i<100000; i++)
        {
            Map<String, String> m = c.getMap();
            System.out.println("At "+i+": "+m.get("X"));
            c.setMap(m);
        }
    }

    private Map<String, String> map;
    Map<String, String> getMap()
    {
        // It's a good practice to only return unmodifiable VIEWS
        // on internal data structures:
        return Collections.unmodifiableMap(map);        
    }
    void setMap(Map<String, String> map)
    {
        this.map = map;
    }


}

直到现在,这只是一个猜测,但这是我能想到的唯一可能的原因(除非您在某处进行了一些讨厌的反射黑客).

Until now, this is just a guess, but the only possible reason that I can think of (unless you're doing some nasty reflection hacks somewhere).

为了检测在这里是否确实存在这种情况,您可以尝试在最终调用 Map#get 的方法上设置一个断点,并在调试器中检查对象.

In order to detect whether this is actually the case here, you might try to set a breakpoint at the method that eventually calls Map#get, and inspect the object in the debugger.

这篇关于来自Collections.unmodifiableMap get()的StackOverflowError吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆