네로개발일기

개발자 네로의 개발 일기, 자바를 좋아합니다 !

'2021/09'에 해당되는 글 10건


반응형

💻 OS: mac m1 os

❓Error: bundle install 또는 rails db:create 사용할 때 발생하는 에러

 

 

macOS (m1)에서 bundle install을 할 때 생기는 에러이다. (while bundle install for mysql2 gem ruby on mac)

둘 중에 한 에러가 뜰 수 있다. (나는 둘 다 번갈아서 에러가 발생했다.)

ld: library not found for -lzstd (zstd 라이브러리를 찾지 못함)

ld: library not found for -lssl (ssl 라이브러리를 찾지 못함)

$ bundle install
(생략)
Installing mysql2 0.5.3 with native extensions

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
current directory:
/Users/jyjeon/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3/ext/mysql2
/Users/jyjeon/.rbenv/versions/2.6.5/bin/ruby -I
/Users/jyjeon/.rbenv/versions/2.6.5/lib/ruby/2.6.0 -r
./siteconf20210928-15542-ky3uai.rb extconf.rb
--with-ldflags\=-L/opt/homebrew/Cellar/zstd/1.5.0/lib
checking for rb_absint_size()... yes
checking for rb_absint_singlebit_p()... yes
checking for rb_wait_for_single_fd()... yes
-----
Using mysql_config at /opt/homebrew/bin/mysql_config
-----
checking for mysql.h... yes
checking for errmsg.h... yes
checking for SSL_MODE_DISABLED in mysql.h... yes
checking for SSL_MODE_PREFERRED in mysql.h... yes
checking for SSL_MODE_REQUIRED in mysql.h... yes
checking for SSL_MODE_VERIFY_CA in mysql.h... yes
checking for SSL_MODE_VERIFY_IDENTITY in mysql.h... yes
checking for MYSQL.net.vio in mysql.h... yes
checking for MYSQL.net.pvio in mysql.h... no
checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes
checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes
checking for my_bool in mysql.h... no

-----
Don't know how to set rpath on your system, if MySQL libraries are not in path
mysql2 may not load
-----
-----
Setting libpath to /opt/homebrew/Cellar/mysql/8.0.26/lib
-----
(생략)
make "DESTDIR=" clean
(생략)
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2
(생략)
An error occurred while installing mysql2 (0.5.3), and Bundler cannot

continue.

In Gemfile:
  mysql2

 

$ rails db:create
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lzstd
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

이런 에러가 발생한다.

해결책은 bundle clean을 해주면 안 되는 경우가 있다. 그럴 경우 --force를 통해 해 준다.

bundle clean --force
brew uninstall mysql
brew install mysql

mysql이 깔려있을 경우 brew를 사용해서 삭제 후 재설치

 

1) ld: library not found for -lssl (ssl 라이브러리를 찾지 못함)

bundle config --local build.mysql2 "--with-cppflags=-I/usr/local/opt/openssl/include"

2) ld: library not found for -lzstd (zstd 라이브러리를 찾지 못함)

bundle config --local build.mysql2 "--with-ldflags=-L/opt/homebrew/Cellar/zstd/1.5.0/lib"

두 명령어 중 하나를 실행해주면 된다.

되지 않을 때는  sudo명령어를 사용해서 실행함.

gem install mysql2 -v '0.5.3' -- --with-opt-dir=$(brew --prefix openssl) --with-ldflags=-L/opt/homebrew/Cellar/zstd/1.5.0/lib

 

라이브러리 위치를 찾지 못해서 생기는 문제 같다.

 

출처

https://stackoverflow.com/questions/67840691/ld-library-not-found-for-lzstd-while-bundle-install-for-mysql2-gem-ruby-on-mac

 

ld: library not found for -lzstd while bundle install for mysql2 gem Ruby on macOS Big Sur 11.4

while running bundle install An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue. Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds

stackoverflow.com

 

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

# try-finally 보다는 try-with-resources를 사용하라

## 1. 자원이 닫힘을 보장하는 수단, try-finally의 단점

- 코드 가독성에 있어 지저분하다.

- 두번째 예외가 첫번째 예외를 집어삼켜버러 실제 시스템에서 디버깅을 어렵게한다.

static void copy(String src, String dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutStream out = new FileOutStream(dst);
        try {
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while((n = in.read(buf)) >= 0) 
                out.write(buf, 0, n);
        }finally {
            out.close();
        }
    }finally {
        in.close();
    }
}

 

 

## 2. 자원 회수의 최선책 try-with-resources

- AutoCloseable 인터페이스 구현: close() 메서드 하나만 정의

public interface AutoCloseable {
    void close() throws Exception;
}
static void copy(String src, String dst) throws IOException {
    try (InputStream in = new FileInputStream(src);
        OutStream out = new FileOutStream(dst)) {
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while((n = in.read(buf)) >= 0) 
                out.write(buf, 0, n);
    } catch (IOException e) {
        return defaultValue;
    }
}

- 읽기 쉽고 문제 진단에 유리하다.

- catch를 이용해 try문을 중첩하지 않고도 다수의 예외 처리가 가능하다.

- 숨겨진 예외도 버려지지 않고, suppressed 꼬리표를 달고 출력된다.

 

readLine()과 close() 호출 양쪽에서 예외가 발생하면, close() 예외는 숨겨지고 readLine()에서 발생한 예외가 기록된다.  



728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

finalizer와 cleaner 사용을 피해라

## 1. 자바의 객체 소멸자

- finalizer: 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다. 오동작, 낮은 성능, 이식성 문제의 원인이다. **"쓰지 말자"** 자바 9에서는 사용 자제(deprecated) API로 지정

- cleaner: finalizer보단 덜 위험하지만, 여전히 예측할 수 없고, 느리고, 일반적으로 불필요하다.

 

* C++의 파괴자(destructor): 특정 객체와 관련된 자원을 회수하는 보편적인 방법 (Java의 try-with-resources, try-finally)

* Java의 가비지 컬렉터: 접근할 수 없게된 객체를 회수

 

## 2. finalizer와 cleaner 사용을 피해야 하는 이유

### 1) 즉시 수행된다는 보장이 없다.

객체에 접근할 수 없게 된 이후부터 실행되기까지 얼마나 걸릴지 알 수 없다. 제때 실행되어야 하는 작업은 절대 할 수 없다.   

수행 시점이 전적으로 GC 알고리즘에 달렸으며, 구현 방식에 따라 천차만별이다.     

finalizer 쓰레드는 다른 애플리케이션보다 우선순위가 낮다. 

 

### 2) 수행 여부도 보장하지 않는다.

접근할 수 없는 객체에 딸린 종료작업을 수행하지 못한 채 프로그램이 중단될 수도 있다. 

상태를 영구적으로 수정하는 작업에서 절대 finalizer나 cleaner에 의존해서는 안된다.   

System.gc, System.runFinalization 메서드에 현혹되지 말자. 실행 가능성은 높여주나 보장해주진 않는다.     

 

### 3) finalizer 동작 중 발생한 예외가 무시되며, 처리할 작업이 남아있어도 그 순간 종료된다.

잡지 못한 예외로 객체가 덜 마무리된 상태로 남아있을 수 있다. 훼손된 객체를 사용하려 할 때 예측할 수 없다.   

 

### 4) finalizer와 cleaner은 심각한 성능문제도 동반한다.

AutoCloseable 객체를 생성해 GC 수거시간: 12ns   

finalizer 수거시간: 550ns -> GC의 효율을 떨어뜨린다.    

 

### 5) finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수도 있다.

생성자나 직렬화 과정에서 예외가 발생하면 생성되다 만 객체에서 악의적인 하위 클래스의 finalizer가 수행될 수 있다.    

객체 생성을 막으려면 생성자에서 예외를 던지면 되는데, finalizer가 있으면 그렇지도 않다.     

final이 아닌 클래스를 finalizer 공격으로부터 방어하려면 아무 일도 하지 않는 finalize 메서드를 만들고 final로 선언하자.

 

## 3. finalizer, cleaner의 대안

AutoClosable을 구현하고, 클라이언트에서 인스턴스를 다 쓰면 close 메서드를 호출한다. 예외가 발생해도 잘 종료되도록 try-with-resources를 사용한다.

 

## 4. finalizer, cleaner의 쓰임새

### 1) 자원의 소유자가 close메서드를 호출하지 않는 것에 대비한 안전망 역할

안전망 역할의 finalizer를 작성할 때는 그럴만한 값어치가 있는지 심사숙고하자.    

자바 라이브러리의 일부 클래스는 안전망 역할의 finalizer를 제공한다: FileInputStream, FileOutputStream, ThreadPoolExecutor   

 

### 2) 네이티브 피어와 연결

네이티브 피어(native peer): 일반 자바 객체가 네이티브 메서드를 통해 기능을 위임한 네이티브 객체. 자바 객체가 아니라 가비지 컬렉터는 그 존재를 알지 못한다.      

성능 저하를 감당할 수 있고 네이티브 피어가 심각한 자원을 가지고 있지 않을 때에만 해당된다. 성능 저하를 감당할 수 없거나 네이티브 피어가 사용하는 자원을 즉시 회수해야 한다면 close 메서드를 사용하자.   

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

# 다 쓴 객체 참조를 해제하라

Java의 장점 중 하나는 가비지 컬렉션을 지원하는 언어라는 점  

하지만, 가비지 컬렉션을 통해 소멸 대상이 되는 객체가 되기 위해서는 어떠한 reference 변수에서 가르키지 않아야 한다. 다 쓴 객체에 대한 참조를 해제하지 않으면 가비지 컬렉션의 대상이 되지 않아 계속 메모리가 할당되는 메모리 누수 현상이 발생된다.    

가비지 컬렉션을 지원하는 언어에서는 메모리 누수를 찾기가 까다롭다. 객체 참조(reference)를 하나 살려두면, 가비지 컬렉터는 그 객체뿐만 아니라 그 객체 내에서 참조하고 있는 객체까지 회수할 수 없다.   

 

## 1. 직접 할당 해제

- 객체 참조 변수를 null로 초기화한다.

- 실제 Heap 메모리에 존재하는 객체는 어떤 참조(reference)도 가지지 않기 때문에 가비지 컬렉션의 소멸 대상이 된다.

- 클래스 내에서 메모리를 관리하는 객체라면 이 방법을 통해 다 쓴 객체는 할당을 해제하는 것이 옳다.

 

## 2. Scope을 통한 자동 할당 해제

- 보통은 변수 선언과 동시에 초기화를 사용한다. 그 변수에 대한 scope가 종료되는 순간 reference가 해제되어 가비지 컬렉션의 대상이 된다.

- try-catch 와 같은 구문에서는 finally 구문에서 변수에 대한 참조를 해제한다.

 

## 메모리 누수의 주범

1. 자기 메모리를 직접 관리하는 클래스

- 클래스 내에서 인스턴스에 대한 참조(reference)를 관리하는 객체

- 프로그래머가 항시 메모리 누수에 주의한다.

 

2. 캐시 (Map)

- 캐시에 객체 참조를 넣고, 객체를 다 쓴 후에도 놔두는 경우

- 해결책)

    - WeakHashMap을 이용해 캐시를 만든다. 외부에서 키를 참조하는 동안만 엔트리가 살아있는 캐시

    - 시간이 지날수록 엔트리 가치를 떨어뜨리는 방식 -> ScheduledThreadPoolExecutor(쓰지 않는 엔트리 청소)

 

3. 리스너(listener), 콜백(callback)

- 클라이언트가 콜백만 등록하고 해지하지 않는 경우, 계속 쌓인다.

- 해결책)

    - 콜백을 약한 참조(weak reference)로 저장한다. WeakHashMap에 키로 저장한다.

 

## Java Reference

### GC의 reachability

- reachable: 어떤 객체에 유효한 참조가 있다. (root set: 유효한 최초의 참조)

- unreachable: 어떤 객체에 유효한 참조가 없다. (GC 대상)

 

### java.lang.ref 패키지의 객체 참조 종류 4가지

1. Strong Reference

- 우리가 흔히 사용하는 참조

- String str = new String("hello"); 와 같은 형태

- Strong Reference는 GC의 대상이 아니다.

- Strong Reference 관계의 객체가 GC의 대상이 되기 위해서 null로 초기화해 객체에 대한 reachability 상태를 unreachable 상태로 만들어줘야 한다.

 

2. Soft Reference

- 객체의 reachability가 strongly reachable 객체가 아닌 객체 중 Soft Reference만 있는 상태

- SoftReference<Class> ref = new SoftReference<>(new String("hello")); 와 같은 형태

- Soft Reference는 대게 GC대상이 아니다가 out of memory 에러가 나기 직전에 Soft Reference 관계에 있는 객체들은 GC 대상이 된다.

 

3. Weak Reference

- 객체의 reachability가 strongly reachable 객체가 아닌 객체 중 Soft Reference가 없고 Weak Reference만 있는 상태

- WeakReference<Class> ref = new WeakReference<Class>(new String("hello")); 와 같은 형태

- WeakReference는 GC 동작마다 회수된다.

- WeakReference 객체 내의 weakly reachable 객체에 대한 참조가 null로 설정되면, GC에 의해 메모리 회수

WeakReference<Sample> wr = new WeakReference<Sample>(new Sample());
Sample ex = wr.get(); // 참조
ex = null; // weakly reachable 객체 = null -> 메모리 회수

 

 

4. Phantomly Reference

- 객체의 reachability가 strongly reachable 객체가 아닌 객체 중 Soft Reference와 Weak Referencerk 모두 해당되지 않는 객체

- finalize 되었지만 메모리가 아직 회수 되지 않은 객체

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !

반응형

# 불필요한 객체 생성을 피하라

 

## 1. 객체 재사용

똑같은 기능의 객체를 매번 생성하는 것보다 객체 하나를 생성해서 재사용하는 편이 좋다. 불변 객체는 언제든지 재사용할 수 있다.     

// bad example - 호출될 때마다 새로운 인스턴스 생성
String s = new String("bad example"); // Heap 영역에 존재

// good example - 하나의 인스턴스를 사용
String s = "good example"; // String constant pool 영역에 존재 (Perm > Heap)

- 같은 JVM에서 똑같은 문자열 리터럴을 사용하는 경우 모든 코드가 같은 객체를 재사용하는 것이 보장된다.      

- String constant pool 영역에 있는지 검색 후, String 객체를 재사용한다. (== 연산자로 비교 가능 ! )

 

## 2. 정적 팩터리 메서드를 제공하는 불변 클래스

public Boolean(String s) { // 생성자 - Java9에서 deprecated
    this(parseBoolean(s));
}

public static Boolean valueOf(String s) { // 정적 팩터리 메서드
    return parseBoolean(s) ? TRUE : FALSE;
}
boolean b = new Boolean("false");
boolean b = Boolean.valueOf("true");

- 생성자는 매번 새로운 객체를 생성하지만, 팩터리 메서드는 그렇지 않으므로 Boolean(String s) 생성자 대신 Boolean.valueOf(String s) 팩터리 메서드를 사용하는 것이 좋다.

 

## 3. 생성 비용이 비싼 객체라면 캐싱하여 재사용

// 정규 표현식을 활용해 유효한 로마 숫자인지 확인하는 메서드
static boolean isRomanNumeral(String s) {
    return s.matches("^(?=.)M*(C[MD]|D?C{0,3})" + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
}

- 문제) String.matches() 메서드를 사용

public boolean matches(String regex) {
    return Pattern.matches(regex, this);
}

- String.matches 메서드 내부에서 만드는 정규표현식용 Pattern 인스턴스는 한 번 쓰고 버려져 곧 바로 가비지 컬렉션의 대상이 된다.

- Pattern은 입력받은 정규 표현식에 해당하는 유한 상태 머신(finite state machine)을 만들어 인스턴스 생성 비용이 높다.

- 해결) 생성 비용이 많이 드는 객체가 반복해서 필요하다면, 캐싱하여 재사용하는 것을 권장한다.

public class RomanNumerals {

    private static final Pattern ROMAN = Pattern.compile("^(?=.)M*(C[MD]|D?C{0,3})" + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");

    static boolean isRomanNumeralFast(String s) {
        return ROMAN.matcher(s).matches();
    }
}

- 클래스가 초기화된 후 이 메서드를 한 번도 호출하지 않는다면, ROMAN 필드는 필요없이 초기화된 것이다. lazy initialization으로, 지연 초기화는 코드를 복잡하게 만드는데, 성능은 크게 개선되지 않을 때가 많으므로 권하지 않는다.

 

## 4. 어댑터 패턴 사용

- Map 인터페이스의 keySet 메서드는 Map 객체안의 키를 전부 담은 Set 뷰를 반환한다.

- 뷰 객체를 여러개 만드는 것이 아니라 매번 같은 인스턴스를 반환한다. 

```java

@DisplayName("keyset은 같은 Map을 바라본다.")
@Test
void keyset() {

    Map<String, Object> map = new HashMap<>();
    map.put("Effective Java", "Hello");

    Set<String> Set1 = map.keySet();
    Set<String> Set2 = map.keySet();
    assertThat(Set1).isSameAs(Set2);
}

 

## 5. 오토박싱(autoboxing)

- auto boxing은 기본 타입과 박싱된 기본 타입을 섞어 쓸 때 자동으로 상호 변환해주는 기술이다. 

- 기본타입과 그에 대응하는 박싱된 기본타입의 구분을 흐려주지만 완전히 없애주진 않는다. 성능에서 좋아진다 볼 수 없다.

private static long sum(){

    Long sum = 0L;

    for (long i = 0; i< Integer.MAX_VALUE; i++) {
        sum += i;
    }

    return sum;
}

- sum 변수를 long이 아닌 Long으로 선언하여 불필요한 인스턴스가 sum += i 연산이 이루어질 때마다 생성되는 것이다. 단순히 sum 타입을 long으로 변경해주어도 성능이 개선된다.

- 박싱된 기본타입보다 기본 타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의해야 한다.

 

## 6. 본인만의 객체 풀(pool)을 만들지 말자

- 가벼운 객체를 다룰때는 직접 만든 객체 풀보다 훨씬 빠르다. (JVM GC) 데이터베이스 연결하는데 생성비용이 워낙 비싸니 재사용이 낫다.

- 방어적 복사가 필요한 상황에서 객체를 재사용했을 때 피해가 필요없는 객체를 반복 생성했을 때 피해보다 훨씬 크다.

728x90
반응형
blog image

Written by ner.o

개발자 네로의 개발 일기, 자바를 좋아합니다 !