mik*_*era 9 java performance caching object immutability
我正在开发一个创建大量小型,不可变Java对象的应用程序.一个例子可能是:
public class Point {
  final int x;
  final int y;
  final int z;
  .....
}
很多Point的实例很可能需要引用相同的(x,y,z)位置.
在应用程序的生命周期中尝试缓存和重用这些对象的程度有多大?处理这种情况的任何特殊技巧?
Jer*_*emy 11
当它成为一个问题.否则你只是在创建一个无用的抽象层.
无论哪种方式,您都可以轻松地使用PointFactory您调用get a来实现它Point,它总是为任何给定的x,y和z返回相同的对象实例.但是,你必须管理什么时候应该从缓存中删除点,因为它们不会被垃圾收集.
我说忘了它,除非它是一个实际的问题.您的应用程序不应该依赖于这样的缓存机制,这将允许您在以后必要时添加它.所以也许只是使用一个工厂,它现在很快就会返回一个新的点实例.
public class PointFactory{
    public static Point get(int x, int y, int z){
        return new Point(x, y, z);
    }
}
您可能遇到的问题是使对象池重量轻,比仅创建对象便宜.您希望池足够大,以获得相当高的命中率.
根据我的经验,您可能会遇到微观基准问题.当您在微基准测试中重复创建单个对象类型时,您可以获得比在实际/复杂应用程序中创建各种对象时更好的结果.
许多对象池aproaches的问题在于它们a)需要一个密钥对象,其成本与创建一个简单对象一样多或更多,b)涉及一些同步/锁定,这可能与创建一个对象一样多的成本c)需要一个添加到缓存时的额外对象(例如Map.Entry),意味着您的命中率必须要高得多才能使缓存值得.
我知道最轻量级但是愚蠢的缓存策略是使用带有哈希码的数组.
例如
private static final int N_POINTS = 10191; // or some large prime.
private static final Point[] POINTS = new Point[N_POINTS];
public static Point of(int x, int y, int z) {
    int h = hash(x,y,z); // a simple hash function of x,y,z
    int index = (h & 0x7fffffff) % N_POINTS;
    Point p = POINTS[index];
    if (p != null && p.x == x && p.y == y && p.z == z)
       return p;
    return POINTS[index] = new Point(x,y,z);
}
注意:该数组不是线程安全的,但由于Point是不可变的,因此无关紧要.缓存在尽力而为的基础上工作,并且通过非常简单的逐出策略自然地限制了大小.
出于测试目的,您可以添加命中/未命中计数器以确定数据集的缓存有效性.