Java变量分配数组对象?

Java变量分配数组对象?,java,variadic-functions,Java,Variadic Functions,哇!我刚刚意识到Java中的varargs方法会导致在调用它们时分配数组。不知道为什么我会期望有什么不同,但是否应该为阵列提供某种池?至少对于最初的0到8种尺寸?在Java中,是否有任何解决方法可以使用varargs而不会为每个调用分配数组 编辑:请理解,向GC泄漏内存是不必要的开销/延迟。它不像某些评论所暗示的那样是一个bug。Java有GC并不意味着你可以随意创建大量垃圾。参见EnumSet的示例。vararg方法 of(E first, E... rest) 超载 of(E e1, E

哇!我刚刚意识到Java中的varargs方法会导致在调用它们时分配数组。不知道为什么我会期望有什么不同,但是否应该为阵列提供某种池?至少对于最初的0到8种尺寸?在Java中,是否有任何解决方法可以使用varargs而不会为每个调用分配数组


编辑:请理解,向GC泄漏内存是不必要的开销/延迟。它不像某些评论所暗示的那样是一个bug。Java有GC并不意味着你可以随意创建大量垃圾。

参见
EnumSet
的示例。vararg方法

of(E first, E... rest) 
超载

of(E e1, E e2) 
of(E e1, E e2, E e3) 
of(E e1, E e2, E e3, E e4) 
of(E e1, E e2, E e3, E e4, E e5) 
避免在arg为5或更少时创建vararg数组。(这里的枚举集可能太过分了)

我认为这不是GC真正关心的问题。创建的数组被很快地取消引用,这样的垃圾应该对GC几乎没有影响


然而,实例化一个数组是一个相对昂贵的操作;由于EnumSet.add()非常快,因此创建数组的开销非常明显;他们可能做了一些基准测试,并决定对最多5个参数使用重载进行优化。

请参见
EnumSet
的示例。vararg方法

of(E first, E... rest) 
超载

of(E e1, E e2) 
of(E e1, E e2, E e3) 
of(E e1, E e2, E e3, E e4) 
of(E e1, E e2, E e3, E e4, E e5) 
避免在arg为5或更少时创建vararg数组。(这里的枚举集可能太过分了)

我认为这不是GC真正关心的问题。创建的数组被很快地取消引用,这样的垃圾应该对GC几乎没有影响


然而,实例化一个数组是一个相对昂贵的操作;由于EnumSet.add()非常快,因此创建数组的开销非常明显;他们可能做了一些基准测试,并决定对最多5个参数进行重载优化是值得的。

记住,在现代JVM中,分配短期对象通常非常便宜。在大多数情况下,这不值得担心

虚拟机可以尝试使用某种缓存,但我怀疑正确使用这种缓存的复杂性会超过任何好处,并且可能最终会分配更多的对象


如果您确实希望避免在一个紧密的循环中创建varargs数组,那么没有任何东西可以阻止您创建自己的数组并直接将其传入,如下所示:

void twiddle(String... args) { ... }

void twiddleAllData() {
    String[] args = new String[2];

    for (Data d : getData()) {
        args[0] = d.getFirst();
        args[1] = d.getSecond();
        twiddle(args);
    }
}

请注意,在本例中,对
twidle
的所有调用必须只传递2个参数,因为这是创建的共享数组的大小。

请记住,在现代JVM中,分配短期对象通常非常便宜。在大多数情况下,这不值得担心

虚拟机可以尝试使用某种缓存,但我怀疑正确使用这种缓存的复杂性会超过任何好处,并且可能最终会分配更多的对象


如果您确实希望避免在一个紧密的循环中创建varargs数组,那么没有任何东西可以阻止您创建自己的数组并直接将其传入,如下所示:

void twiddle(String... args) { ... }

void twiddleAllData() {
    String[] args = new String[2];

    for (Data d : getData()) {
        args[0] = d.getFirst();
        args[1] = d.getSecond();
        twiddle(args);
    }
}


请注意,在本例中,对
twidle
的所有调用必须正好传递2个参数,因为这是创建的共享数组的大小。

内存泄漏到底是什么意思?你是说在应用程序的生命周期内,分配给varargs的数组永远不会被释放吗?请发布一些示例代码来演示这个问题,在过去15年中,数百万开发人员似乎没有注意到这个问题。我很清楚:向GC泄漏内存。这不是一个bug。同样:内存泄漏“到GC”,这意味着它会给GC造成开销,换句话说,如果由于创建垃圾而调用太多次,就会触发GC。有趣的是,你以为我在说瓦拉格斯有一只虫子。我明天可以发布一些代码来显示它。我只是觉得阵列可以在内部汇集或其他什么的。你是说,比如说,漏水到排水管?哇!看起来这个问题可能会泄露给GC。你说的泄露内存到底是什么意思?你是说在应用程序的生命周期内,分配给varargs的数组永远不会被释放吗?请发布一些示例代码来演示这个问题,在过去15年中,数百万开发人员似乎没有注意到这个问题。我很清楚:向GC泄漏内存。这不是一个bug。同样:内存泄漏“到GC”,这意味着它会给GC造成开销,换句话说,如果由于创建垃圾而调用太多次,就会触发GC。有趣的是,你以为我在说瓦拉格斯有一只虫子。我明天可以发布一些代码来显示它。我只是觉得阵列可以在内部汇集或其他什么的。你是说,比如说,漏水到排水管?哇!看起来这个问题可能会泄露给GC。所以有一堆方法来避免varargs是解决方法吗?这很好,但是这些重复的方法会污染你的界面。也许我会用这些变体扩展一个虚拟接口,只是为了不污染主接口?还有其他解决办法吗?可能不会…在大多数情况下不用麻烦了。但是假设您有一个类似于
intsum(int…args)
的方法,vararg的开销可能会相对过大;由于调用者通常只使用很少的参数来调用它,因此用固定参数的方法重载vararg版本是非常有益的。@不可更改的,只调用几个参数应该会导致转义分析(只要它足够常见)和内联。@bestsss实验表明情况并非如此,JVM还没有那么聪明。而内联依赖于调用方方法体的复杂性,API设计者可能不想受制于此。@bestsss好吧,我们想知道VM今天做了什么;不是它所能做到的。有什么证据可以证明这个小案子<代码>整数[]arr=新整数[M];对于(intj=0;jSo)来说,有一系列方法来避免varargs是一种解决方法?这很好,但它会污染您与这些变量的接口