When you declare the variable as memory, you'll have to pay extra gas for reserving the memory and more important, you'll also have to SLOAD the complete record, which in your case will be 4 SLOAD operations (4x200 gas). Later in your code, you profit from the cheap MLOAD, but you'll need to access a field more than 4 times, so the 4 SLOADs before are paying off.
In the case with variable declared with storage, you have no additional costs for reserving the memory and you are not preloading from storage. You'll have a single SLOAD only, which is cheaper. However, if you would have more than 4 field accesses, your gas costs would soon exceed the costs of the variant with the memory modifer.
Hence, there is no universal solution for this. It depends on the circumstances.
Finally, this optimization-task is something that can and should be done by the compiler. I hope to see this soon in solc.
emitting Events makes use of a log
storage, which as you've noted is a 4th form of contract information that is much cheaper than the other three kinds of accessible from solidity (memory, storage, stack). EVM nodes are not required to keep logs forever and can garbage collect old logs to save space. Dapps listening for these logs cannot rely on them being persisted forever (e.g. really old events), but can probably listen to new events as a means of updating on changes.
My favorite article about EVM events / log storage is here
https://blog.qtum.org/how-solidity-events-are-implemented-diving-into-the-ethereum-vm-part-6-30e07b3037b9
Although I don't know the exact rationale of the EVM designers, I would guess they wanted to provide a cheap, but not free, way of storing information from contracts and publishing notification information for outside listeners (not on the blockchain). Free storage would be open to abuse / denial-of-service attacks.
In particular from the article, we can compare the cost of storing in logs versus storing in storage
(the choice of names is mildly confusing and regrettable, but what can you do). That would address your question of LOG
versus SSTORE
opcodes.
Don’t forget the memory used, which is 3 gas per byte:
MemoryGas uint64 = 3
Wait what? It costs only 8 gas per byte of log data? That’s 256 gas for 32 bytes, and 96 gas for the memory use. So 322 gas versus 20000 gas for storing the same amount of data in storage, only 1.7% of the cost!
Best Answer
By default, all storage locations have zero value on the EVM. So when you change a slot from zero to non-zero, the overall size of the state increases. This means, all the nodes have to allocate extra storage to accommodate for the new slot you created. However, when you change a non-zero to another non-zero, it doesn't increase the overall size of the EVM state. That storage slow was already occupying some space and it's just rewritten. Hence the difference in gas used.
Additionally, some gas is refunded when you delete some variable, when the
SSTORE
orSELFDESTRUCT
opcode is executed, as it frees up storage. Read more