Jak wyczyscic tablice?Czy wystarczy np.
a = null;
i bedzie oki?Czy jest jakas metoda?Przegrzebalem klase java.util Class
Arrays ale nie znalazlem jakies metody.
Pozdrawiam
Jarek Z.
Będzie "oki". Oba zresztą sposoby są poprawne. Różnice mogą kryć się w
wydajności ogólnej (algorytmy GC kontra fill()) -- trudno jednak
jednoznacznie stwierdzić co i kiedy będzie szybsze?...
Array.fill() to prosta pętla przypisująca każdemu elementowi podaną
wartość, jeśli wykonuje się sporo takich czyszczeń, a tablica nie jest
za duża, to wypełnianie może okazać się szybsze od algorytmów GC
sprzątających przy każdym przejściu także instancję tablicy ...
Przeważnie jednak algorytmy GC zwycięsko z pojedynku wychodzą.
Nieco inaczej sytuacja się ma, gdy trzeba, by początkową wartością
tablicy było coś innego niż wartość domyślna, wtedy pętlę taką w celu
przygotowania "nowej tablicy" trzeba będzie i tak wykonać.
Jeśli nadto tablica jest duża, to wypełnianiem tablicy najlepiej samemu
się zająć :) ... a największym problemem jest wtedy stwierdzenie, czy
tablica jest już duża?...
Zainteresowanym proponuję porównanie wydajności Array.fill() z czymś takim:
public static void fill(Object[] a, int fromIndex, int toIndex, Object
val) {
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex+")");
if (fromIndex < 0)
throw new ArrayIndexOutOfBoundsException(fromIndex);
if (toIndex > a.length)
throw new ArrayIndexOutOfBoundsException(toIndex);
final int size = toIndex - fromIndex;
final int threshold = size < 24 ? size :
(size < 48 ? ((size >> 1) + (size & 1)) : 16);
int s = 0;
for(; s < threshold; ++s)
a[fromIndex + s] = val;
for(; s <= size - s; s <<= 1)
System.arraycopy(a, fromIndex, a, fromIndex + s, s);
if (s < size)
System.arraycopy(a, fromIndex, a, fromIndex + s, size - s);
}
P.S.
Eksperymentalnie dobrany został 'threshold' (Java 1.5.0 i W2K). Gdyby
komuś ciekawsza formuła na myśl przyszła, to za chęć podzielenia się nią
TIA!
piotr
U mnie jest ta twoja metoda jakies 4 razy szybsza... ale opcja "-server"
powoduje ze twoja jest szybsza o 12%.
Niech mi ktos wyjasni z jakiego powodu SUN nie weźmie maszyny server do
JRE i jako default?? w JRE jest tylko hotspot, który jakos najwyrazniej
niebardzo kwapi sie zeby kompilowac to co trzeba :|... no ale za to
uruchamia jakies 2 sekundy szybciej... Kali nie kumać.
Hmmm... u mnie opcja -server nie zmienia aż tak drastycznie osiągów
Arrays.fill().
Może próbowałeś z wcześniejszą Javą ? ... w 'piątce' poprawiono
wydajność, m.in. właśnie System.arraycopy() (choć tu akurat nie więcej
niż 10%) ...
Mógłbyś może podać wyniki testów podobnych moim (źródło na końcu) ?
Jeśli komuś wskaźnik 't0/t1%' znacznie odbiega od podanych tutaj, to
gdy poinformować tu o wynikach swych zechce, także mile widzianym będzie.
Środowisko testowe:
Windows 2000, 1 x CPU 2,4GHz, 1GB RAM
C:\Java\testy>java -version
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode, sharing)
C:\Java\testy>java -Xprof ArrayFillTest 10000 5000 10
t0: 1031
t1: 203
t0: 1032
t1: 203
t0: 1015
t1: 204
t0: 1031
t1: 203
t0: 1031
t1: 188
t0: 1016
t1: 203
t0: 1031
t1: 203
t0: 1032
t1: 187
t0: 1047
t1: 187
t0: 1032
t1: 203
args: size=10000, loops=5000, trys=10
t0 avg: 1029 (min/max: 1015/1047)
t1 avg: 198 (min/max: 187/204)
t0/t1%: 519,70%
Flat profile of 12.34 secs (842 total ticks): main
Interpreted + native Method
0.1% 1 + 0 java.util.Currency.getInstance
0.1% 1 + 0 ArrayFillTest.main
0.1% 1 + 0 java.util.jar.JarFile.hasClassPathAttribute
0.1% 0 + 1 java.io.FileOutputStream.writeBytes
0.5% 3 + 1 Total interpreted
Compiled + native Method
82.3% 693 + 0 java.util.Arrays.fill
14.0% 118 + 0 ArrayFillTest.fill
2.0% 17 + 0 ArrayFillTest.main
1.2% 10 + 0 java.util.Arrays.fill
99.5% 838 + 0 Total compiled
Flat profile of 0.01 secs (1 total ticks): DestroyJavaVM
Thread-local ticks:
100.0% 1 Blocked (of total)
Global summary of 12.35 seconds:
100.0% 844 Received ticks
C:\Java\testy>java -server -Xprof ArrayFillTest 10000 5000 10
t0: 1219
t1: 234
t0: 1203
t1: 172
t0: 781
t1: 203
t0: 594
t1: 203
t0: 594
t1: 203
t0: 610
t1: 203
t0: 593
t1: 204
t0: 593
t1: 203
t0: 594
t1: 188
t0: 593
t1: 203
args: size=10000, loops=5000, trys=10
t0 avg: 737 (min/max: 593/1219)
t1 avg: 201 (min/max: 172/234)
t0/t1%: 366,67%
Flat profile of 9.45 secs (641 total ticks): main
Interpreted + native Method
0.3% 2 + 0 ArrayFillTest.fill
0.2% 1 + 0 java.util.Arrays.fill
0.2% 1 + 0
java.security.BasicPermission.newPermissionCollection
0.2% 0 + 1 java.io.FileOutputStream.writeBytes
0.2% 0 + 1 java.util.zip.ZipFile.open
0.2% 0 + 1 java.lang.System.arraycopy
0.2% 1 + 0 java.util.ResourceBundle.getLoader
0.2% 1 + 0 ArrayFillTest.fill
0.2% 0 + 1 java.lang.Class.getComponentType
0.2% 1 + 0 ArrayFillTest.main
1.7% 7 + 4 Total interpreted
Compiled + native Method
52.4% 335 + 1 ArrayFillTest.main
28.7% 184 + 0 adapters
17.0% 109 + 0 ArrayFillTest.fill
0.2% 1 + 0 java.util.Arrays.fill
98.3% 629 + 1 Total compiled
Flat profile of 0.00 secs (1 total ticks): DestroyJavaVM
Thread-local ticks:
100.0% 1 Blocked (of total)
Global summary of 9.46 seconds:
100.0% 643 Received ticks
0.5% 3 Compilation
C:\Java\testy>java -Xint -Xprof ArrayFillTest 10000 5000 10
t0: 3437
t1: 235
t0: 3437
t1: 219
t0: 3437
t1: 219
t0: 3453
t1: 219
t0: 3437
t1: 235
t0: 3437
t1: 219
t0: 3453
t1: 219
t0: 3437
t1: 235
t0: 3437
t1: 219
t0: 3453
t1: 219
args: size=10000, loops=5000, trys=10
t0 avg: 3441 (min/max: 3437/3453)
t1 avg: 223 (min/max: 219/235)
t0/t1%: 1543,05%
Flat profile of 36.71 secs (2525 total ticks): main
Interpreted + native Method
92.9% 2346 + 0 java.util.Arrays.fill
5.6% 0 + 142 java.lang.System.arraycopy
1.1% 27 + 0 ArrayFillTest.fill
0.1% 2 + 0 java.util.Arrays.rangeCheck
0.1% 0 + 2 java.io.FileOutputStream.writeBytes
0.1% 2 + 0 ArrayFillTest.fill
0.0% 1 + 0 java.util.HashMap.<init>
0.0% 1 + 0 java.util.Formatter.setZero
0.0% 1 + 0 java.util.jar.JarFile.hasClassPathAttribute
0.0% 1 + 0 ArrayFillTest.main
100.0% 2381 + 144 Total interpreted
Flat profile of 0.00 secs (1 total ticks): DestroyJavaVM
Thread-local ticks:
100.0% 1 Blocked (of total)
Global summary of 36.72 seconds:
100.0% 2526 Received ticks
piotr
--
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import static java.lang.System.out;
public class ArrayFillTest {
private static void rangeCheck(int arrayLen, int fromIndex, int
toIndex) {
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex+")");
if (fromIndex < 0)
throw new ArrayIndexOutOfBoundsException(fromIndex);
if (toIndex > arrayLen)
throw new ArrayIndexOutOfBoundsException(toIndex);
}
public static void fill(Object[] a, Object val) {
fill(a, 0, a.length, val);
}
public static void fill(Object[] a, int fromIndex, int toIndex,
Object val) {
rangeCheck(a.length, fromIndex, toIndex);
final int size = toIndex - fromIndex;
final int threshold = size < 24 ? size :
(size < 48 ? ((size >> 1) + (size & 1)) : 16);
int s = 0;
for(; s < threshold; ++s)
a[fromIndex + s] = val;
for(; s <= size - s; s <<= 1)
System.arraycopy(a, fromIndex, a, fromIndex + s, s);
if (s < size)
System.arraycopy(a, fromIndex, a, fromIndex + s, size - s);
}
public static void main(String[] args) {
int size = Integer.parseInt(args[0]);
int loops = Integer.parseInt(args[1]);
int trys = Integer.parseInt(args[2]);
Object[] a = new Object[size];
fill(a, "0");
for(Object o : a)
assert o == "0";
fill(a, "1");
for(Object o : a)
assert o == "1";
long t;
ArrayList<Long> t0s = new ArrayList<Long>();
ArrayList<Long> t1s = new ArrayList<Long>();
for(int n = 0; n < trys; ++n) {
t = System.currentTimeMillis();
for(int i = 0; i < loops; ++i) {
Arrays.fill(a, "0");
Arrays.fill(a, "1");
}
t = System.currentTimeMillis() - t;
out.println("t0: "+ t);
t0s.add(t);
t = System.currentTimeMillis();
for(int i = 0; i < loops; ++i) {
fill(a, "0");
fill(a, "1");
}
t = System.currentTimeMillis() - t;
out.println("t1: "+ t);
t1s.add(t);
}
out.printf("args: size=%d, loops=%d, trys=%d\n",
size, loops, trys);
t = 0;
for(Long l : t0s) t += l;
long avg_t0 = t/trys;
out.printf("t0 avg: %d (min/max: %d/%d)\n",
avg_t0, min(t0s), max(t0s));
t = 0;
for(Long l : t1s) t += l;
long avg_t1 = t/trys;
out.printf("t1 avg: %d (min/max: %d/%d)\n",
avg_t1, min(t1s), max(t1s));
out.printf("t0/t1%%: %.2f%%\n",
(double)avg_t0/avg_t1*100);
}
}
piotr
Ja napisalem sobie cos takiego, nie tak ogolne jak twoje.
Po dodaniu rozbiegówki to z opcja "-server" Arrays.fill() jest nawet
mikroskopijnie szybsze. Wyniki tego i twojego testu podam w nastepnym
poscie.
package test;
import java.util.Arrays;
public class Test {
public static void main(String[] args) throws Exception{
Object[] arr=new Object[1<<16];
//rozbiegówka
for(int i=0;i<10000;i++){
Test.fill(arr,0,arr.length,Test.class);
}
for(int i=0;i<10000;i++){
Arrays.fill(arr,0,arr.length,Test.class);
}
//prawdziwy test
long time=System.nanoTime();
for(int i=0;i<10000;i++){
Arrays.fill(arr,0,arr.length,Test.class);
}
System.out.println(System.nanoTime()-time);
time=System.nanoTime();
for(int i=0;i<10000;i++){
Test.fill(arr,0,arr.length,Test.class);
}
System.out.println(System.nanoTime()-time);
}
public static void fill(Object[] a, int fromIndex, int toIndex, Object
val) {
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex+")");
if (fromIndex < 0)
throw new ArrayIndexOutOfBoundsException(fromIndex);
if (toIndex > a.length)
throw new ArrayIndexOutOfBoundsException(toIndex);
java version "1.5.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_02-b09)
Java HotSpot(TM) Server VM (build 1.5.0_02-b09, mixed mode)
AMD Athlon 64 3400+ (2200) 512 DDR333 WinXP HE
w moim tescie:
(pierwsze Arrays.fill() czas w nano)
5228906188
1248224286
z opcja server:
1160008605
1164233722
W twoim (10000 5000 10):
t0: 781
t1: 156
t0: 797
t1: 141
t0: 797
t1: 140
t0: 797
t1: 156
t0: 782
t1: 156
t0: 781
t1: 156
t0: 782
t1: 140
t0: 797
t1: 141
t0: 812
t1: 157
t0: 812
t1: 156
args: size=10000, loops=5000, trys=10
t0 avg: 793 (min/max: 781/812)
t1 avg: 149 (min/max: 140/157)
t0/t1%: 532,21%
z opcja server:
t0: 719
t1: 188
t0: 703
t1: 156
t0: 313
t1: 156
t0: 156
t1: 156
t0: 157
t1: 140
t0: 156
t1: 157
t0: 156
t1: 156
t0: 156
t1: 141
t0: 156
t1: 157
t0: 156
t1: 156
args: size=10000, loops=5000, trys=10
t0 avg: 282 (min/max: 156/719)
t1 avg: 156 (min/max: 140/188)
t0/t1%: 180,77%
(czas w milisekundach, pierwsze Arrays.fill())
4953
1109
z -server
1344
1109
I jeszcze trochę wyników, tym razem dla:
Windows 95, Duron 800, 128M RAMu
---
java version "1.5.0_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_02-b09)
Java HotSpot(TM) Client VM (build 1.5.0_02-b09, mixed mode)
args: size=10000, loops=5000, trys=10
t0 avg: 2307 (min/max: 2300/2310)
t1 avg: 440 (min/max: 380/500)
t0/t1%: 524,32%
args: size=65536, loops=200, trys=10
t0 avg: 1021 (min/max: 990/1050)
t1 avg: 665 (min/max: 660/710)
t0/t1%: 153,53%
28569389362
16588386496
i to samo z opcją -server:
args: size=10000, loops=5000, trys=10
t0 avg: 1147 (min/max: 820/2200)
t1 avg: 440 (min/max: 390/500)
t0/t1%: 260,68%
args: size=65536, loops=200, trys=10
t0 avg: 989 (min/max: 940/1040)
t1 avg: 675 (min/max: 660/710)
t0/t1%: 146,52%
17401712232
16633976433
---
java version "1.4.2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-b28)
Java HotSpot(TM) Client VM (build 1.4.2-b28, mixed mode)
args: size=10000, loops=5000, trys=10
t0 avg: 2164 (min/max: 2140/2200)
t1 avg: 445 (min/max: 430/500)
t0/t1%: 486.29213483146066
args: size=65536, loops=200, trys=10
t0 avg: 989 (min/max: 980/990)
t1 avg: 658 (min/max: 650/660)
t0/t1%: 150.30395136778117
24450
16470
i z opcją -server:
args: size=10000, loops=5000, trys=10
t0 avg: 1413 (min/max: 990/3520)
t1 avg: 444 (min/max: 380/540)
t0/t1%: 318.2432432432432
args: size=65536, loops=200, trys=10
t0 avg: 1125 (min/max: 1090/1210)
t1 avg: 643 (min/max: 600/770)
t0/t1%: 174.96111975116642
17310
15270
Czyli, jak widać, bywa to różnie... nigdy jednak na korzyść
Arrays.fill() ...
Jednego tylko jeszcze tu nie rozumiem, czemu nasze testy, różnią się tak
istotnie i to tylko w przypadku opcji -server --- mój test dla
size=65536 jest bardzo zbliżony do Twojego (bliższy jeszcze byłby z
loops=5000, z 200 wychodzi jednak podobnie...) -- umie ktoś może to
wyjaśnić ?
piotr
> Czyli, jak widać, bywa to różnie... nigdy jednak na korzyść
> Arrays.fill() ...
> Jednego tylko jeszcze tu nie rozumiem, czemu nasze testy, różnią się tak
> istotnie i to tylko w przypadku opcji -server --- mój test dla
> size=65536 jest bardzo zbliżony do Twojego (bliższy jeszcze byłby z
> loops=5000, z 200 wychodzi jednak podobnie...) -- umie ktoś może to
> wyjaśnić ?
Obstawialbym ze jest to tych kilka instrukcji SSE któregostam ktorymi
nasze procki sie roznia, moze to byc kwestia innej architekury
procka/systemu i "dopasowania" kompilatora w JVM do architekrury, ale
ciezko powiedziec, moze jakbys dal dluzsza rozbiegowke to Arrays.fill()
by wygralo tak jak u mnie, ale ciezko powiedziec.