Zwalnianie pamięci w tablicy, unset, $tab[1] = null

0

Witam, mam taki kod:

<?php
$tab = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);

unset($tab[10]);
unset($tab[1]);
//unset($tab[2]);
//$tab[5] = null;
for($x =0 ; $x < count($tab); $x++)
{
	echo $tab[$x]," ";
}
echo "</br>ILE: ".count($tab);

//var_dump($tab);
?>

Chcę usunąć dwa elementy w tablicy 15 elementowej. Jeśli użyje unset to count zwróci 13 i pętlą już nie wyświetli dwóch ostatnich elementów, natomiast przy indeksach które usunąłem wyświetli info że Undefined offset. Natomiast jak do danego indeksu przypisze null to count zwróci 15 i pętlą wyświetli wszystkie elementy i warning się nie pojawi, no ale czy pamięć zostanie zwolniona, a i tak musi przejść pętlą przez elementy z null? Bo jeśli załóżmy w milionowej tablicy, pół miliona damy na null to przy wyświetlaniu pętla i tak musi milion razy przejść. Szukam takiego rozwiązania żeby po usunięciu/zwolnieniu dwóch elementów tablica nie miała tych dwóch elementów i wszystkie indeksy od [0] do [n] były wypełnione wartościami, żeby żaden element nie miał null i nie zwracał warninga że Undefined offset.

1

Skorzystaj z array_values lub napisz ifa który sprawdzi, czy wartość pod danym indeksem istnieje lub ewenutalnie napisz pętlę, w której ręcznie poprzestawiasz indeksy na te zgodne z kolejnością.

<?php
$arr = [5, 7, 2, 3, 9];
unset($arr[1]);
unset($arr[3]);

$slots = 0;

// $elements_quantity = ...

for($i=0;$i<$elements_quantity;++$i) {

  // body loop of indexes
  
}
?>
2
sentence napisał(a):

Chcę usunąć dwa elementy w tablicy 15 elementowej. Jeśli użyje unset to count zwróci 13 i pętlą już nie wyświetli dwóch ostatnich elementów,

Nie, co najwyżej pętla nie wywali się na elementach usuniętych a nie ostatnich.

$array = ['a','b','v'];
unset ($array[1]);
var_dump($array);
foreach($array as $key =>$value){
    echo ' key: '.$key. ' value: '.$value."\n";
}
$new = array_values($array);
var_dump($array);
var_dump($new);

Nie wiem co chcesz uzyskać, ale jeśli chodzi o iterację to możesz użyć zwykłego prostego foreach. Przy jego użyciu brany jest następny element tablicy i tyle. Na upartego możesz zrobić sortowanie tablicy jeśli to tablica nie asocjacyjna, ale jak walczysz o pamięć to raczej nie tędy droga.

2

użyj funkcji array_splice do usuwania elementu z tablicy to wtedy indexy będą wszystkie po kolei.

$tab = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);

array_splice($tab, 10, 1);
array_splice($tab, 1, 1;

for($x =0 ; $x < count($tab); $x++)
{
    echo $tab[$x]," ";
}
0
mr_jaro napisał(a):

użyj funkcji array_splice do usuwania elementu z tablicy to wtedy indexy będą wszystkie po kolei.

$tab = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);

array_splice($tab, 10, 1);
array_splice($tab, 1, 1;

for($x =0 ; $x < count($tab); $x++)
{
    echo $tab[$x]," ";
}

O to właśnie mi chodzi. Tylko szkoda że nie da się najpierw określić jakie elementy chcemy usunąć a potem wykonać array_splice. Bo jeśli z tej mojej tablicy chcemy usunąć liczbę 5 i 10 to trzeba wykonać:

$tab = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);
array_splice($tab, 4, 1);
array_splice($tab, 8, 1);
print_r($tab);

trzeba pamiętać że po usunięciu liczby 5 wszystkie indeksy przysuwają się o jeden i liczba 10 nie ma już indeksu 9 tylko 8. I przy większej liczbie elementów do usunięcia mamy mały kłopot. A co z ustawieniem elementu na null? pamieć jest wtedy zwolniona?

1

Przeanalizuj ten kod i zobacz jak rośnie użycie pamięci nawet przy ustawieniu elementu nawet na Null. Dopiero jak zadziała Garbage Collection to pamięć jest zwalniana( pamięć np. zwalniana jest przy wywołaniu czynności w funkcji). Jeśli więc głównym Twoim celem jest optymalizacja pamięci to musisz zwrócić uwagę również na sposób pisania kodu. Dodatkowo jeszcze odśmiecanie i jego mechanizmy na pewno zależą od samej wersji PHP, u mnie testowane na PHP 7.3.12

$arr=[];
for($i=0;$i<1000;$i++){
    $int =0;
    for($z=0;$z<1000;$z++){
        $int+=$z;
    }
    $arr[]=$int;
}
echo (memory_get_usage());
echo "\n";
for($i=0;$i<1000;$i++){
    if($i%2==0){
        $array[$i]=Null;
    }
}
echo (memory_get_usage());
echo "\n";
for($i=0;$i<1000;$i++){
    if($i%2==0){
        unset($array[$i]);
    }
}
echo (memory_get_usage());
echo "\n";
$arr=[];
for($i=0;$i<1000;$i++){
    $int =0;
    for($z=0;$z<1000;$z++){
        $int+=$z;
    }
    $arr[]=$int;
}
echo (memory_get_usage());
echo "\n";
for($i=0;$i<1000;$i++){
    if($i%2==0){
        $array[$i]=Null;
    }
}
echo (memory_get_usage());
echo "\n";
function unsetArrayElement($array){
    for($i=0;$i<1000;$i++){
        if($i%2==0){
            unset($array[$i]);
        }
    }
    echo (memory_get_usage());
    echo "\n";
}
unsetArrayElement($array);
echo (memory_get_usage());
echo "\n";
//OUTPUT;
//433312
//453880
//453880
//453880
//453880
//474416
//453880

Dokumentacja PHP: https://www.php.net/manual/en/features.gc.refcounting-basics.php

Z pierwszego postu:

Szukam takiego rozwiązania żeby po usunięciu/zwolnieniu dwóch elementów tablica nie miała tych dwóch elementów i wszystkie indeksy od [0] do [n] były wypełnione wartościami, żeby żaden element nie miał null i nie zwracał warninga że Undefined offset.

Indeksy wszystkie są zapełnione nawet jak zrobisz unset. Array w PHP ma wskaźnik na następny element dlatego może działać foreach bez konieczności wskazywania klucza. Dlatego jak masz po wykonaniu jakichś czynności na tablicy ją całą przeiterować to to jest właściwy sposób.
https://www.php.net/manual/en/function.next.php

1 użytkowników online, w tym zalogowanych: 0, gości: 1