Instead of deleting the items that you want to discard from an array that you are iterating over ... which is a very dicey proposition in any programming language ... just create a new list and push the entries that you want to keep onto it. (The grep function might do this in one fell swoop.) Then, replace the original list with the new one.
@list = grep( &keep_me, @list);
In almost every case, the two lists consist of references to some bit of information ... and a reference, no matter what monstrosity it may refer to, is small and cheap. You’re actually not moving the contents (big) around, just references-to (small) them. As you build the new list, the reference-counts of all its contents briefly rises to “2,” then, when the new list replaces the old one (and the old one vanishes into the gloom of the garbage-collector ...) they all go down again.