Groups are rather annoying objects, as they are highly complex in the way they function yet incredibly easy to interface.
From what I can tell (could be wrong).
When you create a group object, WC3 asigns a hashtable to it, and a list (linked array).
When you add units to it, it firstly hashes the unit in the hashtable, then it adds the unit to the list at the end. The hashtable is used to quickly tell if a group contains a unit or not while the list is used when doing actions like enuming. Overfilling the hashtable will result in slowdowns when setting and retreving if a unit is in a group (adding and removing units). You can not ever overfill the list, and it maintains a constant efficency (however it becomes slower to enum as there is more objects to loop through).
The problem with groups is that units which are removed (eithor by death or by triggers) still leave data in the group. This results in generally slower opperations (hashtables can become full), prevention of handle index recycling (as the unit handle is still stored in it) and unexpected data (enums suddenly are passed a null unit for every removed unit).
Luckilly there are easy fixes to these problems. Removing the unit from the group before it gets removed will free up its position in the group. Clearing the group with the native will remove all these "shadow" units equivently making it a blank new group. Finally destroying the group will free all resources used by the group, so is not a worry if you commonly do that (this is said to have other problems but I have yet to read them).
Groups are handles, this means that when you asign variables to them, you are giving them a pointer and not the object itself. Each variable in WC3 is 32 bits (each index in the case of arrays). Any object which needs less data like a boolean will waste 31 bits of data (not true as there are many kinds of boolean apparently due to a bug). Any object that needs more than 32 bits of data like strings and handles will use a 32 bit pointer which points to the data of the object.
This means that you can asign any number of handle variables to the same handle without any problem and each will point to the same thing in the game.
Let A be a group.
set B = A
set C = A
Both B and C will refer to exactly the same group as A, so if you destroy the group of A then that will also destroy the group that B and C point to. Also if you set A to another different group object, there is no reference left that A ever had a previous group and thus any actions on A will only be done to the last group you assigned A to.
Be aware that most JASS group actions take groups and change their content, while most GUI equivilents will make new groups which they return. Adding, removing and clearing a group will always need a valid group handle to be passed inorder to work, meaning if you destroy the group held in A, never assign A to a new group and then try using any of those natives on A, nothing productive will occur as there is no group being manipulated. In the case of GUI, remeber than most action pieces which give groups will make new groups, which leak unless caught and then destroyed after they are no longer needed.
As a final note, remeber than every handle variable you set to a handle reference will leave a counter attached to that handle index to prevent it being recycled. Thus inorder to let the game recycle handle indexes, it is important to null or change all handle variables once they are no longer holding an active handle object (this removes their garbage collector counters from that handle index) so as to let the game recycle them. Be warned that local handles can cause handle indexes to leak unless you null them by the end of the function due to a bug with WC3 which causes difined ones to not remove garbage collector counters.
Someone should probably add this 780 word post to some wiki or information page or something lol.