- 약한 참조 : 레퍼런스 카운트로 고려되지 않는 레퍼런스 객체

% Reference count(참조수)란?
        : 얼마나 많은 부분에서 객체를 참조하고 있는가를 나타내 주는 정수


sys모듈의 getrefcount는 요소의 레퍼런스카운트 갯수를 반환해줌

1. python을 구현한 내부코드에서 3이란 숫자를 29번 참조했다는 의미

2. 한 변수를 참조하는 다른 변수 또한 같은 메모리 공간을 가리키고 있음

3. 서로 같은 값(256이하)을 가지고 있는 다른 변수는 같은 메모리 공간을 가리킴

4. 257 이상 부터는 같은 값을 저장해도 다른 아이디 값은 가진다. 

%아마도 256까지는 singletone으로 구현되었을 것이다.


**python의 Garbage Collecter의 원리**
        : 레퍼런스 카운트가 0인 경우 사용하지 않는 메모리라고 판단하고 GC가 메모리를 반환한다. 


- weakref.ref()
        : 주어진 객체에 대한 약한 참조를 만들어 낸다. 원 객체를 얻을 때에는 약한 참조 자체를 함수처럼 호출.


- weakref.proxy()
        : 원본객체를 대신하는 프록시 객체로 약한 참조를 얻는다. (약한 참조를 객체로 접근 하는 방법)


- 사용 용도

1. 탱글링 방지(cycle reference : 순환 참조)
    : 서로 다른 객체들 사이에 참조 방식이 순환 형태로 연결되는 방식
    독립적으로 존재하지만 순환 참조되는 서로 다른 객체 그룹은 쓰레기 수집이 잘 안됨.
    주기적으로 수집 기능이 있지만 CPU자원 장비가 심함 > 빈도가 낮으면 메모리 불필요한 메로리 점유

2. caching에 사용하면 효과적
    : 대용량의 이미지 데이터들을 가지고 있을 때, 메모리 관리를 편하게 하기 위해 (local에 제한을 둠) 예제 참고 ExpensiveObject.py
        (불필요한 데이터를 끝까지 가지고 있을 필요 없음)

3. 용량이 큰 객체를 자주 사용하거나, 쉽게 만들 수 있을 때 


ExpensiveObject.py (WeakValueDictionary를 사용하여 약한 참조를 만든다. > 원 객체를 참조를 없애고 가비지 컬렉터를 돌려 약한 참조의 생명주기를 확인한다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import gc
from pprint import pprint
import weakref
 
gc.set_debug(gc.DEBUG_LEAK)
 
class ExpensiveObject(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return 'ExpensiveObject(%s)' % self.name
    def __del__(self):
        print '(Deleting %s)' % self
        
def demo(cache_factory):
    # hold objects so any weak references 
    # are not removed immediately
    all_refs = {}
    # the cache using the factory we're given
    print 'CACHE TYPE:', cache_factory
    cache = cache_factory()
    for name in [ 'one''two''three' ]:
        o = ExpensiveObject(name)
        cache[name] = o
        all_refs[name] = o
        del o # decref
 
    print 'all_refs =',
    pprint(all_refs)
    print 'Before, cache contains:', cache.keys()
    for name, value in cache.items():
        print '  %s = %s' % (name, value)
        del value # decref
        
    # Remove all references to our objects except the cache
    print 'Cleanup:'
    del all_refs
    gc.collect()
 
    print 'After, cache contains:', cache.keys()
    for name, value in cache.items():
        print '  %s = %s' % (name, value)
    print 'demo returning'
    return
 
demo(dict)
print
demo(weakref.WeakValueDictionary)
cs


- 반복자(iterator) 
    : 데이터 타입의 내부 구현을 노출하지 않고 포함하고 있는 요소들을 순회하는 방법

리스트 또는 어떤 컨테이너를 Iterator로 만들려면

def __iter__(self):
    return self

def next(self):
    self.data += 1
    if self.limit and self.limit <= self.data:
       
         raise StopIteration
    return self.data

을 선언해 주면 된다. > iterator가 되었으므로 for문을 돌면서 next 메소드를 호출시켜 준다.

StopIteration을 종료후 던져야 한다.

ex)    


- 발생자 (Generator)
    : return 대신 yield를 사용하는 것

-> 함수 호출된 후에 되돌아갈 때, 메모리가 해제되지 않고 그대로 남아있음
    그리고 다시 그 함수가 호출되면 이전에 수행이 종료되었던 지점 이후를 계속 진행함.

yield : Iterator를 구현할 수 있는 훨씬 간결한 문법을 제공한다.!!


   코드 설명

gen = generate_inits(3) #초기 스택 프레임 발생 / 실행 중단 상태
gen.next()                  #실행 재개
yield                         #실행 중단/ 값 return

- 일반 함수와의 차이점 : 일반 함수는 모든 일을 마친 결과를 넘김, But 정보를 생성하는 중간에 값을 넘길 수 있다.
    > 어떤 작업의 중간 결과를 다른 코드에서 참조해야 할 경우 유용하게 활용됨
    > 병행 프로세스나 멀티쓰레드 처리 업무에도 활용 가능
    > 메모리 효율성에 좋음

+ Recent posts